Texture packer

Want to pack loads of images into one large texture, without wading through loads of academic bin-packing papers?
So did I, so I implemented the algorithm from this page. It’s not terribly clever, but it is quick and easy.

Just throw an item with width and height dimensions at it, and it’s return a rectangle in which the item can reside. Later you can delete the item, and the space will be returned to usable, barring fragmentation.

The only import is java.util.List, and even that’s only for visualisation in the test app. Find the code here.

Free to a good home etc…

I’d like to attach the test app, but the forum won’t let me - says the upload folder is full :-\

Anyhoo, this is what it looks like

http://base.googlehosted.com/base_media?q=hand8735358713223340513&size=1

From playing around with this, you get best performance by sorting the input items and inserting them in descending order of area.

If anyone’s interested I can email you the jar if you PM me.

Cheers for that, it might come in handy (i’ll see if it out performs my naive implementation)

Download the test app here.
You can click on the rectangles to remove them from the tree and exhibit the fragmentation behaviour.

ah, my problem is the other way around.

I have a known set of rectangles, and need to find the smallest texture size (within a given set of min/max dimensions) that will encompass them all.

The power-of-two dimension restriction on textures really cuts down the size of the search space, so it might be feasible to simply try progressively bigger textures until you find one that fits.

For instance, here’s how I’m finding a minimal texture to pack a font into (the glyphs have been sorted for size previously)


	private Dimension calculateTextureSize()
	{
		// mean glyph size
		float mean = 0;
		for( Glyph g : glyphs )
		{
			mean += g.image.getWidth();
			mean += g.image.getHeight();
		}
		mean /= glyphs.size() * 2;

		// initial guess
		int dim = GLUtil.nextPowerOf2( ( int ) ( mean * Math.sqrt( glyphs.size() ) ) ) / 2;
		dim = Math.max( 2, dim );

		Dimension d = new Dimension( dim / 2, dim );
		boolean growWidth = true;

		boolean success = false;

		do
		{
			// alternate expanding horizontally and vertically
			if( growWidth )
			{
				d.setWidth( d.getWidth() * 2 );
			}
			else
			{
				d.setHeight( d.getHeight() * 2 );
			}
			growWidth = !growWidth;

			RectanglePacker<Glyph> packer = new RectanglePacker<Glyph>( d.getWidth(), d.getHeight() );
			Iterator<Glyph> iter = glyphs.iterator();
			boolean fit = true;
			while( fit && iter.hasNext() )
			{
				Glyph g = iter.next();

				fit &= packer.insert( g.image.getWidth(), g.image.getHeight(), g ) != null;
			}

			success = fit;
		}
		while( !success );

		return d;
	}

See this post for an example of the packed texture.

I’m not using it in a situation where power-of-2 textures are a consideration :wink:

Ah well, good luck with that.

Thanks for sharing this! It deserves to be bumped :slight_smile:

Too bad I didn’t find bleb’s post before I set out! :slight_smile: Here is another implementation of the same algorithm:
http://code.google.com/p/skorpios/source/browse/trunk/skorpios-desktop/tools/com/esotericsoftware/skorpios/tools/ImagePacker.java
This one tries increasingly larger POT textures.

I have a bastardized version that aims to find the smallest texture that all the images fit on. Bin packing is an NP-hard problem so you can’t brute force for the best solution. My algorithm tries the images sorted a few different ways before giving up on a size. It also grows only in the X direction for a while, then goes back, increases the Y by one, grows the Y for a while, goes back, increases X by one, grows X for a while, etc.