Merge "Fix Klocwork issues." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / atlas-manager / atlas-manager-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 // CLASS HEADER
18 #include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
19
20 // EXTERNAL INCLUDE
21 #include <iostream>
22 #include <string.h>
23 #include <dali/devel-api/rendering/sampler.h>
24 #include <dali/devel-api/rendering/shader.h>
25 #include <dali/integration-api/debug.h>
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 namespace
37 {
38   const uint32_t DEFAULT_ATLAS_WIDTH( 512u );
39   const uint32_t DEFAULT_ATLAS_HEIGHT( 512u );
40   const uint32_t DEFAULT_BLOCK_WIDTH( 16u );
41   const uint32_t DEFAULT_BLOCK_HEIGHT( 16u );
42   const uint32_t SINGLE_PIXEL_PADDING( 1u );
43   const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
44   const uint32_t FILLED_PIXEL( -1 );
45   Toolkit::AtlasManager::AtlasSize EMPTY_SIZE;
46
47   #define MAKE_SHADER(A)#A
48
49   const char* VERTEX_SHADER = MAKE_SHADER(
50   attribute mediump vec2    aPosition;
51   attribute mediump vec2    aTexCoord;
52   uniform   mediump mat4    uMvpMatrix;
53   uniform   mediump vec3    uSize;
54   varying   mediump vec2    vTexCoord;
55
56   void main()
57   {
58     mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
59     position.xyz *= uSize;
60     gl_Position = uMvpMatrix * position;
61     vTexCoord = aTexCoord;
62   }
63   );
64
65   const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
66   uniform lowp    vec4      uColor;
67   uniform         sampler2D sTexture;
68   varying mediump vec2      vTexCoord;
69
70   void main()
71   {
72     mediump vec4 color = texture2D( sTexture, vTexCoord );
73     gl_FragColor = vec4( uColor.rgb, uColor.a * color.r );
74   }
75   );
76
77   const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
78   uniform         sampler2D sTexture;
79   varying mediump vec2      vTexCoord;
80
81   void main()
82   {
83     gl_FragColor = texture2D( sTexture, vTexCoord );
84   }
85   );
86
87 }
88
89 AtlasManager::AtlasManager()
90 : mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES ),
91   mFilledPixel( FILLED_PIXEL )
92 {
93   mNewAtlasSize.mWidth = DEFAULT_ATLAS_WIDTH;
94   mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT;
95   mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH;
96   mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT;
97   mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
98   mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
99 }
100
101 AtlasManagerPtr AtlasManager::New()
102 {
103   AtlasManagerPtr internal = new AtlasManager();
104   return internal;
105 }
106
107 AtlasManager::~AtlasManager()
108 {
109   for ( SizeType i = 0; i < mAtlasList.size(); ++i )
110   {
111     mAtlasList[ i ].mAtlas.UploadedSignal().Disconnect( this, &AtlasManager::OnUpload );
112     delete[] mAtlasList[ i ].mStripBuffer;
113   }
114
115   // Are there any upload signals pending? Free up those buffer images now.
116   for ( SizeType i = 0; i < mUploadedImages.Size(); ++i )
117   {
118     delete[] mUploadedImages[ i ];
119   }
120 }
121
122 void AtlasManager::OnUpload( Image image )
123 {
124   if ( mUploadedImages.Size() )
125   {
126     delete[] mUploadedImages[ 0 ];
127     mUploadedImages.Erase( mUploadedImages.Begin() );
128   }
129   else
130   {
131     DALI_LOG_ERROR("Atlas Image Upload List should not be empty\n");
132   }
133 }
134
135 Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasManager::AtlasSize& size, Pixel::Format pixelformat )
136 {
137   SizeType width = size.mWidth;
138   SizeType height = size.mHeight;
139   SizeType blockWidth = size.mBlockWidth;
140   SizeType blockHeight = size.mBlockHeight;
141
142   // Check to see if the atlas is large enough to hold a single block even ?
143   if ( blockWidth > width || blockHeight > height )
144   {
145     DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
146                     width, height, blockWidth, blockHeight );
147     return 0;
148   }
149
150   Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
151   atlas.Clear( Vector4::ZERO );
152   mUploadedImages.PushBack( NULL );
153   AtlasDescriptor atlasDescriptor;
154   atlasDescriptor.mAtlas = atlas;
155   atlasDescriptor.mSize = size;
156   atlasDescriptor.mPixelFormat = pixelformat;
157   atlasDescriptor.mTotalBlocks = ( width / blockWidth ) * ( height / blockHeight );
158   atlasDescriptor.mAvailableBlocks = atlasDescriptor.mTotalBlocks - 1u;
159   atlas.UploadedSignal().Connect( this, &AtlasManager::OnUpload );
160
161   // What size do we need for this atlas' strip buffer ( assume 32bit pixel format )?
162   SizeType neededStripSize =( blockWidth > blockHeight - DOUBLE_PIXEL_PADDING ? blockWidth : blockHeight - DOUBLE_PIXEL_PADDING ) << 2;
163   atlasDescriptor.mStripBuffer = new PixelBuffer[ neededStripSize ];
164   memset( atlasDescriptor.mStripBuffer, 0, neededStripSize );
165
166   atlasDescriptor.mHorizontalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
167                                                        blockWidth,
168                                                        SINGLE_PIXEL_PADDING,
169                                                        pixelformat );
170
171   atlasDescriptor.mVerticalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
172                                                      SINGLE_PIXEL_PADDING,
173                                                      blockHeight - DOUBLE_PIXEL_PADDING,
174                                                      pixelformat );
175   mUploadedImages.PushBack( NULL );
176   atlasDescriptor.mFilledPixelImage = BufferImage::New( reinterpret_cast< PixelBuffer* >( &mFilledPixel ), 1, 1, pixelformat );
177   atlas.Upload( atlasDescriptor.mFilledPixelImage, 0, 0 );
178
179   Sampler sampler = Sampler::New( atlas, "sTexture" );
180   sampler.SetProperty( Sampler::Property::AFFECTS_TRANSPARENCY, true );
181   atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
182   atlasDescriptor.mMaterial.AddSampler( sampler );
183   atlasDescriptor.mSampler = sampler;
184   atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
185   mAtlasList.push_back( atlasDescriptor );
186   return mAtlasList.size();
187 }
188
189 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
190 {
191   mAddFailPolicy = policy;
192 }
193
194 void AtlasManager::Add( const BufferImage& image,
195                         Toolkit::AtlasManager::AtlasSlot& slot,
196                         Toolkit::AtlasManager::AtlasId atlas )
197 {
198   // See if there's a slot in an atlas that matches the requirements of this image
199   // A bitmap must be sliceable into a single atlas
200   Pixel::Format pixelFormat = image.GetPixelFormat();
201   SizeType width = image.GetWidth();
202   SizeType height = image.GetHeight();
203   SizeType blockArea = 0;
204   SizeType foundAtlas = 0;
205   SizeType index = 0;
206   slot.mImageId = 0;
207
208   AtlasSlotDescriptor desc;
209
210   // If there is a preferred atlas then check for room in that first
211   if ( atlas-- )
212   {
213     foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea );
214   }
215
216   // Search current atlases to see if there is a good match
217   while( !foundAtlas && index < mAtlasList.size() )
218   {
219     foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea );
220     ++index;
221   }
222
223   // If we can't find a suitable atlas then check the policy to determine action
224   if ( !foundAtlas-- )
225   {
226     if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
227     {
228       SizeType newAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
229       if ( !newAtlas-- )
230       {
231         return;
232       }
233       else
234       {
235         foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea );
236       }
237     }
238
239     if ( !foundAtlas-- || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
240     {
241       // Haven't found an atlas for this image!!!!!!
242       return;
243     }
244   }
245
246   // Work out where the blocks are we're going to use
247   for ( SizeType i = 0; i < blockArea; ++i )
248   {
249     // Is there currently a next free block available ?
250     if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
251     {
252       // Yes, so select our next block
253       desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks-- );
254     }
255     else
256     {
257       // Our next block must be from the free list, fetch from the start of the list
258       desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
259       mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
260     }
261   }
262
263   desc.mImageWidth = width;
264   desc.mImageHeight = height;
265   desc.mAtlasId = foundAtlas + 1u;
266   desc.mCount = 1u;
267
268   // See if there's a previously freed image ID that we can assign to this new image
269   uint32_t imageId = 0u;
270   for ( uint32_t i = 0u; i < mImageList.size(); ++i )
271   {
272     if ( !mImageList[ i ].mCount )
273     {
274       imageId = i + 1u;
275       break;
276     }
277   }
278   if ( !imageId )
279   {
280     mImageList.push_back( desc );
281     slot.mImageId = mImageList.size();
282   }
283   else
284   {
285     mImageList[ imageId - 1u ] = desc;
286     slot.mImageId = imageId;
287   }
288   slot.mAtlasId = foundAtlas + 1u;
289   UploadImage( image, desc );
290 }
291
292 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
293                                                  SizeType width,
294                                                  SizeType height,
295                                                  Pixel::Format pixelFormat,
296                                                  SizeType& blockArea )
297 {
298   if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
299   {
300     // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
301     if ( ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() )
302            && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
303            && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
304     {
305       blockArea = 1u;
306       return ( atlas + 1u );
307     }
308   }
309   return 0u;
310 }
311
312 void AtlasManager::CreateMesh( SizeType atlas,
313                                SizeType imageWidth,
314                                SizeType imageHeight,
315                                const Vector2& position,
316                                SizeType widthInBlocks,
317                                SizeType heightInBlocks,
318                                Toolkit::AtlasManager::Mesh2D& mesh,
319                                AtlasSlotDescriptor& desc )
320 {
321   Toolkit::AtlasManager::Vertex2D vertex;
322   uint32_t faceIndex = 0;       // TODO change to unsigned short when property type is available
323
324   SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
325   SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
326
327   float vertexBlockWidth = static_cast< float >( blockWidth );
328   float vertexBlockHeight = static_cast< float >( blockHeight );
329
330   SizeType width = mAtlasList[ atlas ].mSize.mWidth;
331   SizeType height = mAtlasList[ atlas ].mSize.mHeight;
332
333   SizeType atlasWidthInBlocks = width / blockWidth;
334
335   // Get the normalized size of a texel in both directions
336   // TODO when texture resizing and passing texture size via uniforms is available,
337   //      we will encode pixel positions into the vertex data rather than normalized
338   //      meaning that geometry needn't be changed on an atlas resize
339   float texelX = 1.0f / static_cast< float >( width );
340   float texelY = 1.0f / static_cast< float >( height );
341
342   float halfTexelX = texelX * 0.5f;
343   float halfTexelY = texelY * 0.5f;
344
345   // Get the normalized size of a block in texels
346   float texelBlockWidth = texelX * vertexBlockWidth;
347   float texelBlockHeight = texelY * vertexBlockHeight;
348
349   // Get partial block space
350   float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
351   float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
352
353   // And in texels
354   float texelEdgeWidth = texelX * vertexEdgeWidth;
355   float texelEdgeHeight = texelY * vertexEdgeHeight;
356
357   // We're going to 'blit' half a pixel more on each edge
358   vertexBlockWidth++;
359   vertexEdgeWidth++;
360   vertexBlockHeight++;
361   vertexEdgeHeight++;
362
363    // Block by block create the two triangles for the quad
364   SizeType blockIndex = 0;
365   float ndcWidth;
366   float ndcHeight;
367   float ndcVWidth;
368   float ndcVHeight;
369
370   // Move back half a pixel
371   Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
372
373   for ( SizeType y = 0; y < heightInBlocks; ++y )
374   {
375
376     float currentX = position.x;
377
378     if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
379     {
380       ndcHeight = texelEdgeHeight + texelY;
381       ndcVHeight = vertexEdgeHeight;
382     }
383     else
384     {
385       ndcHeight = texelBlockHeight + texelY;
386       ndcVHeight = vertexBlockHeight;
387     }
388
389     for ( SizeType x = 0; x < widthInBlocks; ++x )
390     {
391       SizeType block = desc.mBlocksList[ blockIndex++ ];
392
393       float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
394       float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
395
396       // Add on texture filtering compensation
397       fBlockX += halfTexelX;
398       fBlockY += halfTexelY;
399
400       if (  ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
401       {
402         ndcWidth = texelEdgeWidth + texelX;
403         ndcVWidth = vertexEdgeWidth;
404       }
405       else
406       {
407         ndcWidth = texelBlockWidth + texelX;
408         ndcVWidth = vertexBlockWidth;
409       }
410
411       // Top left
412       vertex.mPosition.x = topLeft.x;
413       vertex.mPosition.y = topLeft.y;
414       vertex.mTexCoords.x = fBlockX;
415       vertex.mTexCoords.y = fBlockY;
416
417       mesh.mVertices.PushBack( vertex );
418
419       // Top Right
420       vertex.mPosition.x = topLeft.x + ndcVWidth;
421       vertex.mPosition.y = topLeft.y;
422       vertex.mTexCoords.x = fBlockX + ndcWidth;
423       vertex.mTexCoords.y = fBlockY;
424
425       mesh.mVertices.PushBack( vertex );
426
427       // Bottom Left
428       vertex.mPosition.x = topLeft.x;
429       vertex.mPosition.y = topLeft.y + ndcVHeight;
430       vertex.mTexCoords.x = fBlockX;
431       vertex.mTexCoords.y = fBlockY + ndcHeight;
432
433       mesh.mVertices.PushBack( vertex );
434
435       // Bottom Right
436       topLeft.x += ndcVWidth;
437       vertex.mPosition.x = topLeft.x;
438       vertex.mPosition.y = topLeft.y + ndcVHeight;
439       vertex.mTexCoords.x = fBlockX + ndcWidth;
440       vertex.mTexCoords.y = fBlockY + ndcHeight;
441
442       mesh.mVertices.PushBack( vertex );
443
444       // Six indices in counter clockwise winding
445       mesh.mIndices.PushBack( faceIndex + 1u );
446       mesh.mIndices.PushBack( faceIndex );
447       mesh.mIndices.PushBack( faceIndex + 2u );
448       mesh.mIndices.PushBack( faceIndex + 2u );
449       mesh.mIndices.PushBack( faceIndex + 3u );
450       mesh.mIndices.PushBack( faceIndex + 1u );
451       faceIndex += 4;
452     }
453
454     // Move down a row
455     topLeft.x = currentX;
456     topLeft.y += vertexBlockHeight;
457   }
458
459   // If there's only one block then skip this next vertex optimisation
460   if ( widthInBlocks * heightInBlocks > 1 )
461   {
462     Toolkit::AtlasManager::Mesh2D optimizedMesh;
463     OptimizeMesh( mesh, optimizedMesh );
464   }
465 }
466
467 void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
468 {
469   uint32_t vertexCount = mesh.mVertices.Size();
470   uint32_t indexCount = mesh.mIndices.Size();
471   std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
472   std::cout << ", Triangles = " << indexCount / 3 << std::endl;
473
474   for ( SizeType v = 0; v < vertexCount; ++v )
475   {
476     std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
477     std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
478     std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
479     std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
480   }
481
482   std::cout << "\n Indices: ";
483   for ( SizeType i = 0; i < indexCount; ++i )
484   {
485     std::cout << " " << mesh.mIndices[ i ];
486   }
487   std::cout << std::endl;
488 }
489
490 void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
491                                  Toolkit::AtlasManager::Mesh2D& out )
492 {
493   unsigned short vertexIndex = 0;
494
495   // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
496   for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
497   {
498     // Fetch a vertex, has it already been assigned?
499     bool foundVertex = false;
500     Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
501     for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
502     {
503       if ( ( fabsf( v.mPosition.x - out.mVertices[ j ].mPosition.x ) < Math::MACHINE_EPSILON_1000 ) &&
504            ( fabsf( v.mPosition.y - out.mVertices[ j ].mPosition.y ) < Math::MACHINE_EPSILON_1000 ) &&
505            ( fabsf( v.mTexCoords.x - out.mVertices[ j ].mTexCoords.x ) < Math::MACHINE_EPSILON_1000 ) &&
506            ( fabsf( v.mTexCoords.y - out.mVertices[ j ].mTexCoords.y ) < Math::MACHINE_EPSILON_1000 ) )
507       {
508         // Yes, so store this down as the vertex to use
509         out.mIndices.PushBack( j );
510         foundVertex = true;
511         break;
512       }
513     }
514
515     // Did we find a vertex ?
516     if ( !foundVertex )
517     {
518       // No so add a new one
519       out.mVertices.PushBack( v );
520       vertexIndex++;
521     }
522   }
523 }
524
525 void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
526                                const Toolkit::AtlasManager::Mesh2D& second,
527                                bool optimize )
528 {
529   uint32_t vc = first.mVertices.Size();
530
531   for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
532   {
533     first.mVertices.PushBack( second.mVertices[ v ] );
534   }
535
536   for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
537   {
538     first.mIndices.PushBack( second.mIndices[ i ] + vc );
539   }
540
541   if ( optimize )
542   {
543     Toolkit::AtlasManager::Mesh2D optimizedMesh;
544     OptimizeMesh( first, optimizedMesh );
545     first = optimizedMesh;
546   }
547 }
548
549 void AtlasManager::StitchMesh( const Toolkit::AtlasManager::Mesh2D& first,
550                                const Toolkit::AtlasManager::Mesh2D& second,
551                                Toolkit::AtlasManager::Mesh2D& out,
552                                bool optimize )
553 {
554   uint32_t vc = first.mVertices.Size();
555
556   for ( uint32_t v = 0; v < vc; ++v )
557   {
558     out.mVertices.PushBack( first.mVertices[ v ] );
559   }
560
561   for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
562   {
563     out.mVertices.PushBack( second.mVertices[ v ] );
564   }
565
566   for ( uint32_t i = 0; i < first.mIndices.Size(); ++i )
567   {
568     out.mIndices.PushBack( first.mIndices[ i ] );
569   }
570
571   for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
572   {
573     out.mIndices.PushBack( second.mIndices[ i ] + vc );
574   }
575
576   if ( optimize )
577   {
578     Toolkit::AtlasManager::Mesh2D optimizedMesh;
579     OptimizeMesh( out, optimizedMesh );
580     out = optimizedMesh;
581   }
582 }
583
584 void AtlasManager::UploadImage( const BufferImage& image,
585                                 const AtlasSlotDescriptor& desc )
586 {
587   // Get the atlas to upload the image to
588   SizeType atlas = desc.mAtlasId - 1u;
589
590   // Check to see that the pixel formats are compatible
591   if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
592   {
593     DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
594     return;
595   }
596
597   SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
598   SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
599   SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
600
601   SizeType block = desc.mBlocksList[ 0 ];
602   SizeType blockX = block % atlasWidthInBlocks;
603   SizeType blockY = block / atlasWidthInBlocks;
604   SizeType blockOffsetX = blockX * atlasBlockWidth;
605   SizeType blockOffsetY = blockY * atlasBlockHeight;
606
607   SizeType width = image.GetWidth();
608   SizeType height = image.GetHeight();
609
610   // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
611   if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
612                                            blockOffsetX + SINGLE_PIXEL_PADDING,
613                                            blockOffsetY + SINGLE_PIXEL_PADDING ) )
614   {
615     DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
616   }
617   else
618   {
619      mUploadedImages.PushBack( const_cast< BufferImage& >( image ).GetBuffer() );
620   }
621
622   // Blit top strip
623   if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
624                                            blockOffsetX,
625                                            blockOffsetY ) )
626   {
627     DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
628   }
629   else
630   {
631     mUploadedImages.PushBack( NULL );
632   }
633
634   // Blit left strip
635   if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
636                                            blockOffsetX,
637                                            blockOffsetY + SINGLE_PIXEL_PADDING ) )
638   {
639     DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
640   }
641   else
642   {
643     mUploadedImages.PushBack( NULL );
644   }
645
646   // Blit bottom strip
647   if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
648   {
649     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
650                                              blockOffsetX,
651                                              blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
652     {
653       DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
654     }
655     else
656     {
657      mUploadedImages.PushBack( NULL );
658     }
659   }
660
661   // Blit right strip
662   if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
663   {
664     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
665                                              blockOffsetX + width + SINGLE_PIXEL_PADDING,
666                                              blockOffsetY + SINGLE_PIXEL_PADDING ) )
667     {
668       DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
669     }
670     else
671     {
672       mUploadedImages.PushBack( NULL );
673     }
674   }
675 }
676
677 void AtlasManager::GenerateMeshData( ImageId id,
678                                      const Vector2& position,
679                                      Toolkit::AtlasManager::Mesh2D& meshData,
680                                      bool addReference )
681 {
682   // Read the atlas Id to use for this image
683   SizeType imageId = id - 1u;
684   SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
685   SizeType width = mImageList[ imageId ].mImageWidth;
686   SizeType height = mImageList[ imageId ].mImageHeight;
687
688   SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
689   if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
690   {
691     widthInBlocks++;
692   }
693   SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
694   if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
695   {
696     heightInBlocks++;
697   }
698
699   CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
700
701   // Mesh created so increase the reference count, if we're asked to
702   if ( addReference )
703   {
704     mImageList[ imageId ].mCount++;
705   }
706 }
707
708 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
709 {
710   Dali::Atlas null;
711   if ( !atlas || atlas > mAtlasList.size( ) )
712   {
713
714     DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
715     return null;
716   }
717   return mAtlasList[ atlas -1u ].mAtlas;
718 }
719
720 bool AtlasManager::Remove( ImageId id )
721 {
722   // Decrements the reference count of this image, and removes the blocks if zero.
723   SizeType imageId = id - 1u;
724   bool removed = false;
725
726   if ( id > mImageList.size() )
727      {
728     DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
729     return false;
730   }
731
732   // If we attempt to free an image that is already freed then do nothing, other than log
733   if ( !mImageList[ imageId ].mCount )
734   {
735     DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
736     return false;
737   }
738
739   if ( 2u > --mImageList[ imageId ].mCount )
740   {
741     // 'Remove the blocks' from this image and add to the atlas' freelist
742     removed = true;
743     mImageList[ imageId ].mCount = 0;
744     SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
745     for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
746     {
747       mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
748     }
749   }
750   return removed;
751 }
752
753 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
754 {
755   if ( id && id <= mImageList.size() )
756   {
757     return mImageList[ id - 1u ].mAtlasId;
758   }
759   else
760   {
761     return 0;
762   }
763 }
764
765 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
766 {
767   mNewAtlasSize = size;
768   mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
769   mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
770 }
771
772 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
773 {
774   if ( atlas && atlas-- <= mAtlasList.size() )
775   {
776     return mAtlasList[ atlas ].mSize;
777   }
778   return EMPTY_SIZE;
779 }
780
781 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
782 {
783   if ( atlas && atlas-- <= mAtlasList.size() )
784   {
785     return ( mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size() );
786   }
787   else
788   {
789     return 0;
790   }
791 }
792
793 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
794 {
795   return mAtlasList.size();
796 }
797
798 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
799 {
800   if ( !atlas || atlas > mAtlasList.size( ) )
801   {
802
803     DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
804     return Pixel::L8;
805   }
806   return mAtlasList[ --atlas].mPixelFormat;
807 }
808
809 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
810 {
811   Toolkit::AtlasManager::AtlasMetricsEntry entry;
812   uint32_t textureMemoryUsed = 0;
813   uint32_t atlasCount = mAtlasList.size();
814   metrics.mAtlasCount = atlasCount;
815   metrics.mAtlasMetrics.Resize(0);
816
817   for ( uint32_t i = 0; i < atlasCount; ++i )
818   {
819     entry.mSize = mAtlasList[ i ].mSize;
820     entry.mTotalBlocks = mAtlasList[ i ].mTotalBlocks;
821     entry.mBlocksUsed = entry.mTotalBlocks - mAtlasList[ i ].mAvailableBlocks + mAtlasList[ i ].mFreeBlocksList.Size();
822     entry.mPixelFormat = GetPixelFormat( i + 1 );
823
824     metrics.mAtlasMetrics.PushBack( entry );
825
826     uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
827     if ( entry.mPixelFormat == Pixel::BGRA8888 )
828     {
829       size <<= 2;
830     }
831
832     textureMemoryUsed += size;
833
834   }
835   metrics.mTextureMemoryUsed = textureMemoryUsed;
836 }
837
838 Material AtlasManager::GetMaterial( AtlasId atlas ) const
839 {
840   if ( atlas && atlas-- <= mAtlasList.size() )
841   {
842     return mAtlasList[ atlas ].mMaterial;
843   }
844   Material null;
845   return null;
846 }
847
848 Sampler AtlasManager::GetSampler( AtlasId atlas ) const
849 {
850   if ( atlas && atlas-- <= mAtlasList.size() )
851   {
852     return mAtlasList[ atlas ].mSampler;
853   }
854   Sampler null;
855   return null;
856 }
857
858 } // namespace Internal
859
860 } // namespace Toolkit
861
862 } // namespace Dali
863
864