Merge "Add more shared C++/JavaScript docs and add JavaScript wrapping guide" into...
[platform/core/uifw/dali-toolkit.git] / docs / content / shared-javascript-and-cpp-documentation / texture-atlas.md
1 /**
2  *
3 # Texture Atlases {#textureatlases}
4
5 ## Example demo application
6
7 ![ ](../assets/img/texture-atlas/image-wall.jpg)
8 ![ ](image-wall.jpg)
9   
10
11 Application above is running slow as there are many small individual images displayed (50)
12   
13 | Metric | Result | Explanation |
14 |--------|--------|-------------|
15 | Launch time | Slow | Has to perform: 50 file open requests and multiple reads for each image |
16 | Memory consumption|  High | Has to create:50 Dali::Image objects,50 OpenGL Textures|
17 | Rendering | Slow | Has to perform: 50 glBindTexture calls per frame ( each OpenGL calls takes time) 50 a frame = 3000 calls per second @60 FPS.Texture switching is a major state change in the GPU|
18   
19
20
21 ## Solutions to problem: Use a Texture Atlas
22
23 A texture atlas is simply one larger image that contains smaller images. A texture atlas is sometimes called a
24 sprite sheet, bitmap sheet or texture pack.
25
26 ![ ](../assets/img/texture-atlas/atlas.jpg)
27 ![ ](atlas.jpg)
28   
29 Dali::ImageActor has the ability to display a portion of an image using ImageActor::PixelArea setting.
30 For example to display the first 3 image in the atlas
31   
32 ![ ](../assets/img/texture-atlas/example-javascript-code.jpg)
33 ![ ](example-code.jpg)
34
35 ### Result of using an Atlas
36
37 | Metric | Result | Explanation |
38 |--------|--------|-------------|
39 | Launch time | Fast | Has to perform: - 1 file open request  |
40 | Memory consumption|  Low | Has to create: 1 Dali::Image objects 1 OpenGL Textures|
41 | Rendering | Fast | HHas to perform: 1 glBindTexture calls per frame ( each OpenGL calls takes time) 1 a frame = 6- calls per second @60 FPS.|
42
43   
44 ## Atlas creation guide
45
46 Many tools exist for creating texture atlases.
47 In the following example we are using a tool called TexturePacker as DALi has an exporter script for it.
48 The exporter automatically generates a source file that has the ImageActor::PixelArea pre-defined.
49   
50 - Download http://www.codeandweb.com/texturepacker
51 - Launch TexturePacker
52 - Go to the menu File -> Preferences
53 - Set the "Exporter directory" to be the location of dali-toolkit/texture-atlas-exporter
54   
55 ![ ](../assets/img/texture-atlas/texture-packer-preferences.jpg)
56 ![ ](texture-packer-preferences.jpg)
57   
58 - Restart the application!
59 - Select DALi 3D framework for new project
60   
61 ![ ](../assets/img/texture-atlas/texture-packer-startup.jpg)
62 ![ ](texture-packer-startup.jpg)
63   
64 - Create the atlas
65 ![ ](../assets/img/texture-atlas/texture-packer-add-sprites.jpg)
66 ![ ](texture-packer-add-sprites.jpg)
67 - Click publish to produce the files
68 ![ ](../assets/img/texture-atlas/texture-packer-publish.jpg)
69 ![ ](texture-packer-publish.jpg)
70
71
72
73 ## Using the generated cpp ( contains JavaScript code as well)
74
75 The generated cpp file contains 3 different ways of describing the atlas.
76 Copy and paste the section that best suits your application.
77 -  Lookup table. Includes code for storing the table in a std::map for fast lookup.
78 - constants.
79 - JavaScript property map
80
81 ### Using the JavaScript generated property map
82
83 The property map should be cut and paste in to your application. It just looks like
84   
85 ~~~{.js}
86 var ATLAS_IMAGE_LIST : [
87     { name: "add_user_usericon_bg", x: 2, y:109, w:105, h:105,  blendMode:dali.BLENDING_ON  },
88     { name: "app_background", x: 180, y:183, w:1, h:1,  blendMode:dali.BLENDING_OFF  },
89     { name: "btn_arrow_left", x: 141, y:183, w:11, h:20,  blendMode:dali.BLENDING_ON  },
90     { name: "btn_arrow_right", x: 154, y:183, w:11, h:20,  blendMode:dali.BLENDING_ON  },
91     { name: "icn_app_foc", x: 194, y:2, w:72, h:72,  blendMode:dali.BLENDING_ON  },
92     { name: "icn_app_nor", x: 109, y:109, w:72, h:72, blendMode:dali.BLENDING_ON  }
93     ]
94 var atlas = new dali.ResourceImage( { url: "atlas_filename.png" });
95
96 // display the user icon using the size / position data in the ATLAS_IMAGE_LIST
97 var userIconData = ATLAS_IMAGE_LIST[0];
98 var userIconRect = [ userIconData.x, userIconData.y,userIconData.w,userIconData.h];
99
100 var btnArrowLeft = new dali.ImageActor( atlas, userIconRect );
101 btnArrowLeft.setBlendMode(userIconData.blendMode);
102
103 ~~~
104
105 ![ ](example-javascript-code.jpg)
106
107
108 ### Using the lookup table in C++
109
110 Cut and paste the lookup table code into your application.
111
112 ~~~{.cpp}
113
114 // The following code is automatically generated when TexturePacker publishes to a cpp file.
115 const char* ATLAS_FILE_NAME( "my_first_atlas.png" );  ///< Atlas image filename
116
117 // Structure to hold image name and position within the atlas.
118 struct ImageInfo
119 {
120   const char* name;
121   unsigned int x,y,w,h;
122   Dali::BlendingMode::Type blendMode;  // only enable blending if image has alpha
123 };
124
125
126 // lookup table
127 const ImageInfo ImageAtlas[]=
128 {
129  { "blocks-ball", 2, 198, 51, 51, BlendingMode::ON },
130  { "bubble-ball", 288, 74, 32, 32, BlendingMode::ON },
131  { "gallery-small-52", 2, 2, 128, 128, BlendingMode::OFF },
132  { "icon-change", 219, 2, 37, 34, BlendingMode::ON },
133  { "icon-cluster-carousel", 180, 2, 37, 34, BlendingMode::ON }
134 };
135
136 const ImageInfo* GetImageInfo(const char* name)
137 {
138   typedef std::map< const char*, const ImageInfo* > LookupMap;
139   static LookupMap lookup;
140   if( lookup.empty() )
141   {
142     for( unsigned int i = 0; i < ATLAS_IMAGE_COUNT; ++i)
143     {
144       lookup[ ImageAtlas[i].name ] =  &ImageAtlas[i];
145     }
146   }
147   LookupMap::const_iterator iter = lookup.find(name);
148   if( iter != lookup.end() )
149   {
150    return (*iter).second;
151   }
152   DALI_ASSERT_ALWAYS(0 && "image name not found in atlas");
153   return NULL;
154 }
155
156 ~~~
157
158 To use the lookup table you can do something like this:
159
160 ~~~{.cpp}
161 // Example function on how to get an image info from the table
162
163 std::string fileName = std::string( DALI_IMAGE_DIR ) + ATLAS_FILE_NAME;
164 Image imageImage = Image::New( fileName );
165
166 const ImageInfo* info(NULL);
167
168 info = GetImageInfo("blocks-ball");
169 if( info)
170 {
171   ImageActor ballActor = ImageActor::New( imageAtlas, ImageActor::PixelArea( info->x, info->y, info->w, info->h) );
172   ballActor->SetBlendMode( info->blendMode );
173 }
174 info = GetImageInfo("bubble-ball");
175 if( info)
176 {
177   ImageActor bubbleActor = ImageActor::New( imageAtlas, ImageActor::PixelArea( info->x, info->y, info->w, info->h) );
178   bubbleActor->SetBlendMode( info->blendMode );
179 }
180
181 ~~~
182
183 ### Using the constant definitions (C++)
184
185 1. Cut and paste the constant definition code into your application.
186
187 You'll notice the code below won't compile because C++ variables can't have a dash character.
188 E.g. BLOCKS-BALL, BUBBLE-BALL will cause errors. Do a search and replace for - and replace with underscores.
189 This is one reason why using lookup table which holds the filename as a string maybe easier to use.
190   
191 ~~~{.cpp}
192
193 // The following code is automatically generated when TexturePacker publishes to a cpp file.
194 const char* ATLAS_FILE_NAME( "my_first_atlas.png" );
195
196
197 // Structure to hold position / blend mode within the atlas.
198 struct ImageInfo
199 {
200   ImageInfo(unsigned int x,unsigned int y,unsigned int w,unsigned int h,  Dali::BlendingMode::Type mode)
201   :pixelArea(x,y,w,h),blendMode(mode)
202   {}
203   ImageActor::PixelArea pixelArea;
204   Dali::BlendingMode::Type blendMode;  // only enable blending if image has alpha
205 };
206
207
208 const ImageInfo BLOCKS-BALL( 2, 198, 51, 51 ,BlendingMode::ON );
209 const ImageInfo BUBBLE-BALL( 288, 74, 32, 32 ,BlendingMode::ON );
210 const ImageInfo GALLERY-SMALL-52( 2, 2, 128, 128 ,BlendingMode::OFF );
211 ~~~
212   
213   2. To use it, you can copy example code from the generated cpp file which looks
214 like this
215
216 ~~~{.cpp}
217 void LoadAtlasImages()
218 {
219   std::string fileName = std::string(DALI_IMAGE_DIR) + ATLAS_FILE_NAME;
220   Image atlasImage = Image::New( fileName );
221   ImageActor Blocksball = ImageActor::New( atlasImage,  BLOCKS_BALL.pixelArea);
222   Blocksball.SetBlendMode( BLOCKS_BALL.blendMode );
223
224   ImageActor Bubbleball = ImageActor::New( atlasImage,  BUBBLE_BALL.pixelArea);
225   Bubbleball.SetBlendMode( BUBBLE_BALL.blendMode );
226   ...
227 ~~~
228
229
230 ## Atlas creation tips
231
232 - Compress the atlas  - \link Texture_Compression Compressing Textures \endlink
233 - Avoid adding large images to the Atlas.
234 - E.g. don't add background images to it. Medium to large images should be kept seperate.
235   
236 ![ ](../assets/img/texture-atlas/atlas-size.jpg)
237 ![ ](atlas-size.jpg)
238   
239
240 - Try to ensure the atlas contains only images that are frequently used.  There's no point in having images taking up GPU texture memory if they're not displayed.
241 - Avoid very large atlases.   Try to create multiple atlases based on how they are used within your application.
242 Alternatively Texture packer has the option to split atlases ( search help for Multipack)
243
244
245
246 @class _Guide_TextureAtlases
247
248 *
249 */