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