TextField Styling upgrade, Builder to use filenames
[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   AtlasDescriptor atlasDescriptor;
152   atlasDescriptor.mAtlas = atlas;
153   atlasDescriptor.mSize = size;
154   atlasDescriptor.mPixelFormat = pixelformat;
155   atlasDescriptor.mNextFreeBlock = 1u; // indicate next free block will be the first ( +1 )
156   atlas.UploadedSignal().Connect( this, &AtlasManager::OnUpload );
157
158   // What size do we need for this atlas' strip buffer ( assume 32bit pixel format )?
159   SizeType neededStripSize =( blockWidth > blockHeight - DOUBLE_PIXEL_PADDING ? blockWidth : blockHeight - DOUBLE_PIXEL_PADDING ) << 2;
160   atlasDescriptor.mStripBuffer = new PixelBuffer[ neededStripSize ];
161   memset( atlasDescriptor.mStripBuffer, 0, neededStripSize );
162
163   atlasDescriptor.mHorizontalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
164                                                        blockWidth,
165                                                        SINGLE_PIXEL_PADDING,
166                                                        pixelformat );
167
168   atlasDescriptor.mVerticalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
169                                                      SINGLE_PIXEL_PADDING,
170                                                      blockHeight - DOUBLE_PIXEL_PADDING,
171                                                      pixelformat );
172   mUploadedImages.PushBack( NULL );
173   atlasDescriptor.mFilledPixelImage = BufferImage::New( reinterpret_cast< PixelBuffer* >( &mFilledPixel ), 1, 1, pixelformat );
174   atlas.Upload( atlasDescriptor.mFilledPixelImage, 0, 0 );
175
176   Sampler sampler = Sampler::New( atlas, "sTexture" );
177   sampler.SetProperty( Sampler::Property::AFFECTS_TRANSPARENCY, true );
178   atlasDescriptor.mMaterial = Material::New( pixelformat == Pixel::L8 ? mShaderL8 : mShaderRgba );
179   atlasDescriptor.mMaterial.AddSampler( sampler );
180   atlasDescriptor.mSampler = sampler;
181   atlasDescriptor.mMaterial.SetBlendMode( BlendingMode::ON );
182   mAtlasList.push_back( atlasDescriptor );
183   return mAtlasList.size();
184 }
185
186 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
187 {
188   mAddFailPolicy = policy;
189 }
190
191 void AtlasManager::Add( const BufferImage& image,
192                         Toolkit::AtlasManager::AtlasSlot& slot,
193                         Toolkit::AtlasManager::AtlasId atlas )
194 {
195   // See if there's a slot in an atlas that matches the requirements of this image
196   // A bitmap must be sliceable into a single atlas
197   Pixel::Format pixelFormat = image.GetPixelFormat();
198   SizeType width = image.GetWidth();
199   SizeType height = image.GetHeight();
200   SizeType blockArea = 0;
201   SizeType totalBlocks = 0;
202   SizeType foundAtlas = 0;
203   SizeType index = 0;
204   slot.mImageId = 0;
205
206   AtlasSlotDescriptor desc;
207
208   // If there is a preferred atlas then check for room in that first
209   if ( atlas-- )
210   {
211     foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea, totalBlocks );
212   }
213
214   // Search current atlases to see if there is a good match
215
216   while( !foundAtlas && index < mAtlasList.size() )
217   {
218     foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea, totalBlocks );
219     ++index;
220   }
221
222   // If we can't find a suitable atlas then check the policy to determine action
223   if ( !foundAtlas-- )
224   {
225     if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
226     {
227       SizeType newAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
228       if ( !newAtlas-- )
229       {
230         return;
231       }
232       else
233       {
234         foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea, totalBlocks );
235       }
236     }
237
238     if ( Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy || !foundAtlas-- )
239     {
240       // Haven't found an atlas for this image!!!!!!
241       return;
242     }
243   }
244
245   // Work out where the blocks are we're going to use
246   for ( SizeType i = 0; i < blockArea; ++i )
247   {
248     // Is there currently a next free block available ?
249     if ( mAtlasList[ foundAtlas ].mNextFreeBlock )
250     {
251       // Yes, so use this for our next block
252       SizeType selectedBlock = mAtlasList[ foundAtlas ].mNextFreeBlock - 1u;
253       desc.mBlocksList.PushBack( selectedBlock );
254
255       // Any blocks going to be available after this one (adjust to store +1 )?
256       selectedBlock++;
257       selectedBlock++;
258       if ( selectedBlock > totalBlocks )
259       {
260         // No so start trying to use free blocks list
261         selectedBlock = 0;
262       }
263       mAtlasList[ foundAtlas ].mNextFreeBlock = selectedBlock;
264     }
265     else
266     {
267       // Our next block must be from the free list, fetch from the start of the list
268       desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
269       mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
270     }
271   }
272
273   desc.mImageWidth = width;
274   desc.mImageHeight = height;
275   desc.mAtlasId = foundAtlas + 1u;
276   desc.mCount = 1u;
277
278   // See if there's a previously freed image ID that we can assign to this new image
279   uint32_t imageId = 0;
280   for ( uint32_t i = 0; i < mImageList.size(); ++i )
281   {
282     if ( !mImageList[ i ].mCount )
283     {
284       imageId = i + 1u;
285       break;
286     }
287   }
288   if ( !imageId )
289   {
290     mImageList.push_back( desc );
291     slot.mImageId = mImageList.size();
292   }
293   else
294   {
295     mImageList[ imageId - 1u ] = desc;
296     slot.mImageId = imageId;
297   }
298   slot.mAtlasId = foundAtlas + 1u;
299   UploadImage( image, desc );
300 }
301
302 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
303                                                  SizeType width,
304                                                  SizeType height,
305                                                  Pixel::Format pixelFormat,
306                                                  SizeType& blockArea,
307                                                  SizeType& totalBlocks )
308 {
309   if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
310   {
311     // Check to see if there are any unused blocks in this atlas to accomodate our image
312     SizeType blocksInX = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
313     SizeType blocksInY = mAtlasList[ atlas ].mSize.mHeight / mAtlasList[ atlas ].mSize.mBlockHeight;
314     totalBlocks = blocksInX * blocksInY;
315     SizeType blocksFree = mAtlasList[ atlas ].mNextFreeBlock ?
316                           totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u :
317                           mAtlasList[ atlas ].mFreeBlocksList.Size();
318
319     // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
320     if ( blocksFree
321          && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
322          && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
323     {
324       blockArea = 1u;
325       return ( atlas + 1u );
326     }
327   }
328   return 0;
329 }
330
331 void AtlasManager::CreateMesh( SizeType atlas,
332                                SizeType imageWidth,
333                                SizeType imageHeight,
334                                const Vector2& position,
335                                SizeType widthInBlocks,
336                                SizeType heightInBlocks,
337                                Toolkit::AtlasManager::Mesh2D& mesh,
338                                AtlasSlotDescriptor& desc )
339 {
340
341   Toolkit::AtlasManager::Vertex2D vertex;
342   uint32_t faceIndex = 0;       // TODO change to unsigned short when property type is available
343
344   SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
345   SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
346
347   float vertexBlockWidth = static_cast< float >( blockWidth );
348   float vertexBlockHeight = static_cast< float >( blockHeight );
349
350   SizeType width = mAtlasList[ atlas ].mSize.mWidth;
351   SizeType height = mAtlasList[ atlas ].mSize.mHeight;
352
353   SizeType atlasWidthInBlocks = width / blockWidth;
354
355   // Get the normalized size of a texel in both directions
356   // TODO when texture resizing and passing texture size via uniforms is available,
357   //      we will encode pixel positions into the vertex data rather than normalized
358   //      meaning that geometry needn't be changed on an atlas resize
359   float texelX = 1.0f / static_cast< float >( width );
360   float texelY = 1.0f / static_cast< float >( height );
361
362   // Get the normalized size of a block in texels
363   float texelBlockWidth = texelX * vertexBlockWidth;
364   float texelBlockHeight = texelY * vertexBlockHeight;
365
366   // Get partial block space
367   float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
368   float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
369
370   // And in texels
371   float texelEdgeWidth = vertexEdgeWidth * texelX;
372   float texelEdgeHeight = vertexEdgeHeight * texelY;
373
374    // Block by block create the two triangles for the quad
375   SizeType blockIndex = 0;
376   float ndcWidth;
377   float ndcHeight;
378   float ndcVWidth;
379   float ndcVHeight;
380
381   Vector2 topLeft = position;
382
383   for ( SizeType y = 0; y < heightInBlocks; ++y )
384   {
385
386     float currentX = position.x;
387
388     if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
389     {
390       ndcHeight = texelEdgeHeight;
391       ndcVHeight = vertexEdgeHeight;
392     }
393     else
394     {
395       ndcHeight = texelBlockHeight;
396       ndcVHeight = vertexBlockHeight;
397     }
398
399     for ( SizeType x = 0; x < widthInBlocks; ++x )
400     {
401       SizeType block = desc.mBlocksList[ blockIndex++ ];
402
403       float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
404       float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
405
406       // Add on texture filtering compensation
407       fBlockX += texelX;
408       fBlockY += texelY;
409
410       if (  ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
411       {
412         ndcWidth = texelEdgeWidth;
413         ndcVWidth = vertexEdgeWidth;
414       }
415       else
416       {
417         ndcWidth = texelBlockWidth;
418         ndcVWidth = vertexBlockWidth;
419       }
420
421       // Top left
422       vertex.mPosition.x = topLeft.x;
423       vertex.mPosition.y = topLeft.y;
424       vertex.mTexCoords.x = fBlockX;
425       vertex.mTexCoords.y = fBlockY;
426
427       mesh.mVertices.PushBack( vertex );
428
429       // Top Right
430       vertex.mPosition.x = topLeft.x + ndcVWidth;
431       vertex.mPosition.y = topLeft.y;
432       vertex.mTexCoords.x = fBlockX + ndcWidth;
433       vertex.mTexCoords.y = fBlockY;
434
435       mesh.mVertices.PushBack( vertex );
436
437       // Bottom Left
438       vertex.mPosition.x = topLeft.x;
439       vertex.mPosition.y = topLeft.y + ndcVHeight;
440       vertex.mTexCoords.x = fBlockX;
441       vertex.mTexCoords.y = fBlockY + ndcHeight;
442
443       mesh.mVertices.PushBack( vertex );
444
445       // Bottom Right
446       topLeft.x += ndcVWidth;
447       vertex.mPosition.x = topLeft.x;
448       vertex.mPosition.y = topLeft.y + ndcVHeight;
449       vertex.mTexCoords.x = fBlockX + ndcWidth;
450       vertex.mTexCoords.y = fBlockY + ndcHeight;
451
452       mesh.mVertices.PushBack( vertex );
453
454       // Six indices in counter clockwise winding
455       mesh.mIndices.PushBack( faceIndex + 1u );
456       mesh.mIndices.PushBack( faceIndex );
457       mesh.mIndices.PushBack( faceIndex + 2u );
458       mesh.mIndices.PushBack( faceIndex + 2u );
459       mesh.mIndices.PushBack( faceIndex + 3u );
460       mesh.mIndices.PushBack( faceIndex + 1u );
461       faceIndex += 4;
462     }
463
464     // Move down a row
465     topLeft.x = currentX;
466     topLeft.y += vertexBlockHeight;
467   }
468
469   // If there's only one block then skip this next vertex optimisation
470   if ( widthInBlocks * heightInBlocks > 1 )
471   {
472     Toolkit::AtlasManager::Mesh2D optimizedMesh;
473     OptimizeMesh( mesh, optimizedMesh );
474   }
475   //PrintMeshData( mesh );
476 }
477
478 void AtlasManager::PrintMeshData( const Toolkit::AtlasManager::Mesh2D& mesh )
479 {
480   uint32_t vertexCount = mesh.mVertices.Size();
481   uint32_t indexCount = mesh.mIndices.Size();
482   std::cout << "\nMesh Data for Image: VertexCount = " << vertexCount;
483   std::cout << ", Triangles = " << indexCount / 3 << std::endl;
484
485   for ( SizeType v = 0; v < vertexCount; ++v )
486   {
487     std::cout << " Vertex(" << v << ") x = " << mesh.mVertices[v].mPosition.x << ", ";
488     std::cout << "y = " << mesh.mVertices[v].mPosition.y << ", ";
489     std::cout << "u = " << mesh.mVertices[v].mTexCoords.x << ", ";
490     std::cout << "v = " << mesh.mVertices[v].mTexCoords.y << std::endl;
491   }
492
493   std::cout << "\n Indices: ";
494   for ( SizeType i = 0; i < indexCount; ++i )
495   {
496     std::cout << " " << mesh.mIndices[ i ];
497   }
498   std::cout << std::endl;
499 }
500
501 void AtlasManager::OptimizeMesh( const Toolkit::AtlasManager::Mesh2D& in,
502                                  Toolkit::AtlasManager::Mesh2D& out )
503 {
504   unsigned short vertexIndex = 0;
505
506   // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
507   for ( SizeType i = 0; i < in.mIndices.Size(); ++i )
508   {
509     // Fetch a vertex, has it already been assigned?
510     bool foundVertex = false;
511     Toolkit::AtlasManager::Vertex2D v = in.mVertices[ in.mIndices[ i ] ];
512     for ( SizeType j = 0; j < out.mVertices.Size(); ++j )
513     {
514       if ( v.mPosition.x == out.mVertices[ j ].mPosition.x && v.mPosition.y == out.mVertices[ j ].mPosition.y &&
515            v.mTexCoords.x == out.mVertices[ j ].mTexCoords.x && v.mTexCoords.y == out.mVertices[ j ].mTexCoords.y )
516       {
517         // Yes, so store this down as the vertex to use
518         out.mIndices.PushBack( j );
519         foundVertex = true;
520         break;
521       }
522     }
523
524     // Did we find a vertex ?
525     if ( !foundVertex )
526     {
527       // No so add a new one
528       out.mVertices.PushBack( v );
529       vertexIndex++;
530     }
531   }
532 }
533
534 void AtlasManager::StitchMesh( Toolkit::AtlasManager::Mesh2D& first,
535                                const Toolkit::AtlasManager::Mesh2D& second,
536                                bool optimize )
537 {
538   uint32_t vc = first.mVertices.Size();
539
540   for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
541   {
542     first.mVertices.PushBack( second.mVertices[ v ] );
543   }
544
545   for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
546   {
547     first.mIndices.PushBack( second.mIndices[ i ] + vc );
548   }
549
550   if ( optimize )
551   {
552     Toolkit::AtlasManager::Mesh2D optimizedMesh;
553     OptimizeMesh( first, optimizedMesh );
554     first = optimizedMesh;
555   }
556 }
557
558 void AtlasManager::StitchMesh( const Toolkit::AtlasManager::Mesh2D& first,
559                                const Toolkit::AtlasManager::Mesh2D& second,
560                                Toolkit::AtlasManager::Mesh2D& out,
561                                bool optimize )
562 {
563   uint32_t vc = first.mVertices.Size();
564
565   for ( uint32_t v = 0; v < vc; ++v )
566   {
567     out.mVertices.PushBack( first.mVertices[ v ] );
568   }
569
570   for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
571   {
572     out.mVertices.PushBack( second.mVertices[ v ] );
573   }
574
575   for ( uint32_t i = 0; i < first.mIndices.Size(); ++i )
576   {
577     out.mIndices.PushBack( first.mIndices[ i ] );
578   }
579
580   for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
581   {
582     out.mIndices.PushBack( second.mIndices[ i ] + vc );
583   }
584
585   if ( optimize )
586   {
587     Toolkit::AtlasManager::Mesh2D optimizedMesh;
588     OptimizeMesh( out, optimizedMesh );
589     out = optimizedMesh;
590   }
591 }
592
593 void AtlasManager::UploadImage( const BufferImage& image,
594                                 const AtlasSlotDescriptor& desc )
595 {
596   // Get the atlas to upload the image to
597   SizeType atlas = desc.mAtlasId - 1u;
598
599   // Check to see that the pixel formats are compatible
600   if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
601   {
602     DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
603     return;
604   }
605
606   SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
607   SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
608   SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
609
610   SizeType block = desc.mBlocksList[ 0 ];
611   SizeType blockX = block % atlasWidthInBlocks;
612   SizeType blockY = block / atlasWidthInBlocks;
613   SizeType blockOffsetX = blockX * atlasBlockWidth;
614   SizeType blockOffsetY = blockY * atlasBlockHeight;
615
616   SizeType width = image.GetWidth();
617   SizeType height = image.GetHeight();
618
619   // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
620   if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
621                                            blockOffsetX + SINGLE_PIXEL_PADDING,
622                                            blockOffsetY + SINGLE_PIXEL_PADDING ) )
623   {
624     DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
625   }
626   else
627   {
628      mUploadedImages.PushBack( const_cast< BufferImage& >( image ).GetBuffer() );
629   }
630
631   // If this is the first block then we need to keep the first pixel free for underline texture
632   if ( block )
633   {
634
635     // Blit top strip
636     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
637                                              blockOffsetX,
638                                              blockOffsetY ) )
639     {
640       DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
641     }
642     else
643     {
644       mUploadedImages.PushBack( NULL );
645     }
646
647     // Blit left strip
648     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
649                                              blockOffsetX,
650                                              blockOffsetY + SINGLE_PIXEL_PADDING ) )
651     {
652       DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
653     }
654     else
655     {
656       mUploadedImages.PushBack( NULL );
657     }
658   }
659
660   // Blit bottom strip
661   if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
662   {
663     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
664                                              blockOffsetX,
665                                              blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
666     {
667       DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
668     }
669     else
670     {
671      mUploadedImages.PushBack( NULL );
672     }
673   }
674
675   // Blit right strip
676   if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
677   {
678     if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
679                                              blockOffsetX + width + SINGLE_PIXEL_PADDING,
680                                              blockOffsetY + SINGLE_PIXEL_PADDING ) )
681     {
682       DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
683     }
684     else
685     {
686       mUploadedImages.PushBack( NULL );
687     }
688   }
689 }
690
691 void AtlasManager::GenerateMeshData( ImageId id,
692                                      const Vector2& position,
693                                      Toolkit::AtlasManager::Mesh2D& meshData,
694                                      bool addReference )
695 {
696   // Read the atlas Id to use for this image
697   SizeType imageId = id - 1u;
698   SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
699   SizeType width = mImageList[ imageId ].mImageWidth;
700   SizeType height = mImageList[ imageId ].mImageHeight;
701
702   SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
703   if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
704   {
705     widthInBlocks++;
706   }
707   SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
708   if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
709   {
710     heightInBlocks++;
711   }
712
713   CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
714
715   // Mesh created so increase the reference count, if we're asked to
716   if ( addReference )
717   {
718     mImageList[ imageId ].mCount++;
719   }
720 }
721
722 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
723 {
724   Dali::Atlas null;
725   if ( !atlas || atlas > mAtlasList.size( ) )
726   {
727
728     DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
729     return null;
730   }
731   return mAtlasList[ atlas -1u ].mAtlas;
732 }
733
734 bool AtlasManager::Remove( ImageId id )
735 {
736   // Decrements the reference count of this image, and removes the blocks if zero.
737   SizeType imageId = id - 1u;
738   bool removed = false;
739
740   if ( id > mImageList.size() )
741      {
742     DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
743     return false;
744   }
745
746   // If we attempt to free an image that is already freed then do nothing, other than log
747   if ( !mImageList[ imageId ].mCount )
748   {
749     DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
750     return false;
751   }
752
753   if ( 2u > --mImageList[ imageId ].mCount )
754   {
755     // 'Remove the blocks' from this image and add to the atlas' freelist
756     removed = true;
757     mImageList[ imageId ].mCount = 0;
758     SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
759     for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
760     {
761       mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
762     }
763   }
764   return removed;
765 }
766
767 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
768 {
769   if ( id && id <= mImageList.size() )
770   {
771     return mImageList[ id - 1u ].mAtlasId;
772   }
773   else
774   {
775     return 0;
776   }
777 }
778
779 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
780 {
781   mNewAtlasSize = size;
782   mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
783   mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
784 }
785
786 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
787 {
788   if ( atlas && atlas-- <= mAtlasList.size() )
789   {
790     return mAtlasList[ atlas ].mSize;
791   }
792   return EMPTY_SIZE;
793 }
794
795 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
796 {
797   if ( atlas && atlas <= mAtlasList.size() )
798   {
799     uint32_t index = atlas - 1u;
800     uint32_t width = mAtlasList[ index ].mSize.mWidth;
801     uint32_t height = mAtlasList[ index ].mSize.mHeight;
802     uint32_t blockWidth = mAtlasList[ index ].mSize.mBlockWidth;
803     uint32_t blockHeight = mAtlasList[ index ].mSize.mBlockHeight;
804
805     SizeType widthInBlocks = width / blockWidth;
806     SizeType heightInBlocks = height / blockHeight;
807     uint32_t blockCount = widthInBlocks * heightInBlocks;
808
809     // Check free previously unallocated blocks and any free blocks
810     if ( mAtlasList[ index ].mNextFreeBlock )
811     {
812       blockCount -= mAtlasList[ index ].mNextFreeBlock -1u - mAtlasList[ index ].mFreeBlocksList.Size();
813     }
814     else
815     {
816       blockCount = mAtlasList[ index ].mFreeBlocksList.Size();
817     }
818     return blockCount;
819   }
820   else
821   {
822     return 0;
823   }
824 }
825
826 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
827 {
828   return mAtlasList.size();
829 }
830
831 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
832 {
833   if ( !atlas || atlas > mAtlasList.size( ) )
834   {
835
836     DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
837     return Pixel::L8;
838   }
839   return mAtlasList[ atlas -1u ].mPixelFormat;
840 }
841
842 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
843 {
844   Toolkit::AtlasManager::AtlasMetricsEntry entry;
845   uint32_t textureMemoryUsed = 0;
846   uint32_t atlasCount = mAtlasList.size();
847   metrics.mAtlasCount = atlasCount;
848   metrics.mAtlasMetrics.Resize(0);
849
850   for ( uint32_t i = 0; i < atlasCount; ++i )
851   {
852     entry.mSize = mAtlasList[ i ].mSize;
853     entry.mTotalBlocks = ( entry.mSize.mWidth / entry.mSize.mBlockWidth ) * ( entry.mSize.mHeight / entry.mSize.mBlockHeight );
854     uint32_t reuseBlocks = mAtlasList[ i ].mFreeBlocksList.Size();
855     entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock - reuseBlocks - 1u: entry.mTotalBlocks - reuseBlocks;
856     entry.mPixelFormat = GetPixelFormat( i + 1 );
857
858       metrics.mAtlasMetrics.PushBack( entry );
859
860     uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
861     if ( entry.mPixelFormat == Pixel::BGRA8888 )
862     {
863       size <<= 2;
864     }
865
866     textureMemoryUsed += size;
867
868   }
869   metrics.mTextureMemoryUsed = textureMemoryUsed;
870 }
871
872 Material AtlasManager::GetMaterial( AtlasId atlas ) const
873 {
874   if ( atlas && atlas <= mAtlasList.size() )
875   {
876     return mAtlasList[ atlas -1u ].mMaterial;
877   }
878   Material null;
879   return null;
880 }
881
882 Sampler AtlasManager::GetSampler( AtlasId atlas ) const
883 {
884   if ( atlas && atlas <= mAtlasList.size() )
885   {
886     return mAtlasList[ atlas -1u ].mSampler;
887   }
888   Sampler null;
889   return null;
890 }
891
892 } // namespace Internal
893
894 } // namespace Toolkit
895
896 } // namespace Dali
897
898