Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Texture Atlas Maker

4.94/5 (16 votes)
1 Apr 2012BSD6 min read 146.9K   7.1K  
A utility to create texture atlases for 2D OpenGL games
Image 1

Introduction

I've decided to open source our in-house texture atlas creation tool, because I think this will be useful for other independent game developers.

Features

  • Built for speed
Loads textures nearly 5 times faster than loading from PNG
  • One click operation
Streamlines the art pipeline. Creates multiple atlases with multiple formats, all with one click.
  • Open source
Java source code provided, so you can modify the tool for your own needs.

What is a texture atlas?

A texture atlas bin-packs multiple images into a single texture. On some platforms OpenGL textures have to be sized as power of 2, loading the images separately would require a lot of padding, which means wasted GPU memory. As well as that having all images in one texture allows draw-call batching: in other words several sprites can be drawn with one call.

Who is this for?

Although the tool was developed for the iPhone, it is useful for most platforms including Android and PC. The tool is written in Java and runs on Windows, Mac and Linux.

A sample iPhone project is included, that demonstrates loading the texture atlas. The code is c++ and designed to be portable.

How to use

Download the file AtlasMaker_jar_2.2.1.zip and unzip. You will need Java installed on your machine to use it. You may also need to install the PVRTexTool from Imagination Technologies if you want to create PVR compressed textures.

330742/settings4.png

  • Input folder

The source images for your project must be in PNG format and must be organised in directories according to file format. Select the location of the input folder and the directory structure will be shown. Then select the required file format for each directory

  • Targa True Color
This is the default option. Choose this for best quality. Note: targa files have RGB bytes in OpenGL order, so they load faster. This means the file will look odd if you open it on your PC, but it will look fine on the device. The file is 32-bit, or 24 bit if there is no alpha channel.
  • 16-bit Targa
Choosing this option uses only 16-bits per pixel, but reduces the number of colours. Textures with subtle colour changes (i.e. gradients) will look bad.
  • PVR
Compressed PVR format. Uses either 2, or 4-bits per pixel. This format works better with "organic" images with no transparent borders. Note: a padding of 2 pixels is created around each image. This is to prevent pixels appearing from adjacent images (the PVR algorithm draws pixels outside of the image borders).
  • Output file

Select the name and location of the output file. The texture atlases will be saved to the same directory.

Advanced options

Image 3

Click on the "Options..." button to open advanced options.

  • Maximium size
This is the maximum texture size (both width and height) for the device you are targetting.
  • Power-of-two / Non power-of-two
Power of two restricts the size to power of two dimensions (ie. 32x32, 64x32, etc.). Non power-of-two means there is no restriction at all.
  • Alpha threshold
Transparent pixels are trimmed off all source images. The alpha threshold indicates what is considered to be transparent.
  • Location of PVRTexTool
This is the file location where you installed the command line PVRTexTool.
  • PVR Options
When the PVR file format is selected, first the texture atlas will be created as a PNG, then the PVRTexTool will be called to convert it to PVR. This is a slow operation, so by default "Convert PVRs" is deselected.
Choose 2-bit for smaller memory use, but lower quality, or 4-bit for higher quality.
  • XML Format
Choose either the default XML format, or Cocos2D plist format.

Output tabs

A tab is created for each texture. The tab icon hold a preview of the texture. For convenience, clicking anywhere in the texture will display the file name of the image clicked on.

Textures created

The application tries to fit the images in the smallest texture size possible. In the case of power-of-two textures first it tries to fit in 32x32, then 32x64, then 64x64, then 128x64... and so on till the maximum. In the case of Non power-of-two it'll choose the minimum arbitary size automatically. If the images don't in the maximum size texture, additional textures are created until everything fits.

If you choose the PVR format the textures will be square and power-of-two.

Each file will be named by the directory and an index number. E.g. if images are in the directory "images" then the following textures may be created: images0.tga, images1.tga, images2.tga, etc.

Output XML file

The application creates an XML file, which contains all data for each image in each texture atlas, example:

XML
<atlas numImages="4">
  <texture file="testImages0.pvr" trans="true">
    <image name="arch" x="0" y="0" width="89" height="71"/>
    <image name="prowlerBody0_1" x="36" y="342" width="43" height="34" yOffset="5" transWidth="46" transHeight="39"/>
  </texture>
  <texture file="dump0.pvr" trans="true">
    <image name="arrowDownPressed" x="400" y="54" width="46" height="39"/>
    <image name="arrowUpPressed" x="448" y="54" width="46" height="37"/>
  </texture>
</atlas>

First, the "atlas" element tells you total images in atlas, so memory can be pre-allocated when loading.

Then each texture element has the file name, transparency and a list of image elements.

Each image element contains the following data:

  • x, y, width, height
  • The position within the texture and size of the image

  • xOffset, yOffset, transWidth, transHeight
  • Padding data for sprite animations. If we have sprite animations, each sprite needs to be padded so that the image doesn't "jump" around during animation, but we don't want to store the blank space in the texture and waste memory.

    330742/xOffset.png

Why PNG is unsuitable for games

PNG is a complex format and slow to decode. Here are some benchmarks, which show just how slow PNG is:

PNGTarga 32-bit*Targa 16-bit
Loading Windows (libpng) 64 ms9 ms5 ms
Loading iPhone 3GS*385 ms 83 ms
Size1.27 MB2.42 MB1.23 MB
Zipped size1.26 MB1.25 MB339 kB
Loading a 1024 x 1024 texture (complex image with transparency)

As you can see on the iPhone texture loading is 4.6 times slower than 32-bit Targa. Although the Targa file is twice as big it's the same size when zipped, so the package size will be the same. On top of that, if your images only need to be 16-bit quality you get double savings. PNG does not have any 16-bit option.

As you can see, using Targa is a no-brainer.

  • Notes:

PNG decoded on iPhone using native iOS API (i.e. UIImage). Targa is compressed RLE Targa.

Loading Targa

See the ImageTarga and TargaReader classes for details how the targa files are loaded.

Targa 16 bit is stored as GL_UNSIGNED_SHORT_4_4_4_4. However, if the texture atlas is completely opaque the alpha channel is not saved and the pixels are stored as GL_UNSIGNED_SHORT_5_6_5.

If "Targa True Color" is selected then it's saved as either 32-bit or 24-bit, depending on if it has alpha transparency or not.

Demo iPhone project

Included is a xcode project that opens the generated textures and displays a sprite. Most of the code is c++ for portablity.

The following classes are used in the project:

  • Game
Main game object.
  • ResManager
Sets up OpenGL state and initialises all resources
  • AtlasMaster
Reads atlas xml file and creates the AtlasImage objects and textures and stores them in a map for retrieval.
  • XParser
Fast XML parser, with cut down functionality. Parses using forward-only method to avoid the overhead of creating a DOM.
  • TargaReader
Reads 32-bit and 16-bit Targa files
  • CommonBuffer
All texture files are loaded into a shared buffer, rather than creating and deleting each time
  • ImagePVR
Loads PVR textures.
  • AtlasImage
Creates a textured quad for each image.
Note: the project uses boost/unordered_map.hpp. You need to download boost and set the project include headers in xcode to point to where you installed boost. Alternatively, you can change the line: #define fmap boost::unordered_map, to #define fmap std:map in precompile.h

History

Version 2.0

  • Added Non power-of-two functionality
  • Allowed user to specify Maximum texture size
  • Improved atlas creation algorithm
  • Made code more robust

Version 2.1

  • Doesn't save alpha channel if there is no transparency in the texture
  • Fixed bug: Mac version wasn't reading PVRTexTool executable properly

 Version 2.2.1

  • Added support for Cocos2D (with help from Starfair :) )
  • Small improvements in algorithm


License

This article, along with any associated source code and files, is licensed under The BSD License