Cramming the most into a Sprite Atlas - (Bin Packing Problem)

Yes indeed. This texture packing is for the iPhone, too, so it is doubly important for me to be efficient here. I am only packing like-images in each sprite sheet, and I have optimized the rendering pipeline so that pretty much everything will be drawn with just two or three texture binds.

I meant that I didn’t save a seed of those specific objects in the screenshot above, so I can’t get those objects back out no matter how hard I try. If I made a new one, then I could store the seed, but then I wouldn’t be giving Nate the same images. :slight_smile:

I was mostly just curious as to how well the algorithm I used packed something similar to your screenshots.

Most animations have transparency that can be stripped off to save space. This is nice to get more sprites per texture and especially important if you are using PVRTC on the iPhone.

Parsing my tools output on the iPhone goes like this:

@interface PackedImages : NSObject {
	NSMutableDictionary *_nameToImage;
}

- (id) init:(NSString*)packFileName;
- (Image*) getImageNamed:(NSString*)name;
- (BOOL) hasImageNamed:(NSString*)name;

@end


@implementation PackedImages

- (id) init:(NSString*)packFileName {
	self = [super init];
	if (!self) return nil;

	_nameToImage = [[NSMutableDictionary alloc] init];

	NSString *packPath = [[NSBundle mainBundle] pathForResource:packFileName ofType:@"pack"];
	NSLog(@"Loading packed images: %@", packPath);

	FILE *file = fopen([packPath UTF8String], "rt");
	Image *pageImage = nil;
	while (true) {
		char nameString[256];
		if (fscanf(file, "%s", &nameString) == EOF) {
			[pageImage release];
			break;
		}
		NSString *name = [NSString stringWithCString:nameString encoding:NSASCIIStringEncoding];
		if ([name length] == 0) {
			[pageImage release];
			pageImage = nil;
		} else if (pageImage == nil) {
			pageImage = [[Image alloc] initWithImageNamed:name];
		} else {
			int left, top, right, bottom, offsetX, offsetY, index;
			fscanf(file, "%d", &left);
			fscanf(file, "%d", &top);
			fscanf(file, "%d", &right);
			fscanf(file, "%d", &bottom);
			fscanf(file, "%d", &offsetX);
			fscanf(file, "%d", &offsetY);
			if (!fscanf(file, "%d", &index)) index = 9999999;
			Image *image = [[Image alloc] initWithSubImage:pageImage rect:CGRectMake(left, top, right - left, bottom - top)];
			[image setOffset:offsetX y:offsetY];
			[_nameToImage setValue:image forKey:name];
			[image release];
		}
	}

	return self;
}

- (Image*) getImageNamed:(NSString*)name {
	Image* image = [_nameToImage valueForKey:name];
	if (image == nil) NSLog(@"WARN: Packed image not found: %@", name);
	return image;
}

- (BOOL) hasImageNamed:(NSString*)name {
	return [_nameToImage valueForKey:name] != nil;
}

- (void) dealloc {
	[_nameToImage release];
	[super dealloc];
}

@end

Of course, you need a nice Image class. :slight_smile: This doesn’t preserve the order that the Java PackedImages class does. The nice part is the upper left of the image before transparency is stripped is preserved.

My tool already strips transparency. It also gives you the option to force every sprite to be a square, if you so desire, and also saves an animation and atlas file detailing the data in the sheet. Perfect for my exact purpose. :slight_smile: I’ve already got several sprite loaders, atlas loaders, and animation loaders written in ObjC.

Good for you. That doesn’t help anyone else though.

Can’t - have to sort by layer first. And Y coordinate. And sublayer.

Cas :slight_smile:

Did you not notice this thread is about what I needed to do? I wasn’t seeking a way to make something that would be useful for everyone else. :slight_smile:

No problem. I’ll just avoid you and your threads in the future.

This stuff’s pretty cool, I heard that texture binds are expensive so these tools are very useful.

By the way Nate, I think Demonpants/Eli must have had a bad day, he’s not an egotist. Like you, he’s helped me a lot with code and pointers plenty of times 8)

Haha. Sulky Grumples :-*

Cas :slight_smile:

You got it. I did indeed have quite a bad day. More a bad week. Or month. Let me put it this way… this game was originally supposed to be released in June. Due to a large variety of factors, including feature creep, having to work on other projects to raise money, employees getting fired and others getting hired, and more, we are still working on this game (although this time I think the Christmas release date is sound). I am supposed to get a pay bump, health insurance, etc. when the game gets released (depending on how well it does), but most importantly I have been busting my ass for months now (when you have a new release date every month, then every month becomes “crunch time” when you are working too many hours a week and tiring yourself and pissing off your fiancée :P) trying to hit a release date that inevitably gets put off. So it feels a bit like I’ve been wasting time and spinning my wheels for this whole time, not getting anything to actually add to my resume. This week was particularly bad because my computer crashed on Monday so I spent the entire day fixing it, then on Wednesday and Thursday I had to go to a bunch of meetings about yet another project that isn’t this one.

The stress is pouring out of my ear-holes.

Now as for this texture packing tool, I was indeed thinking I would share my source at some point when I had time to fix it up, given that the examples I’ve seen have had many more features than appear to be necessary. Mine is very short, and also uses generics so you can use it to pack anything that has a width and a height. The whitespace trimmer I have in there is external to the actual packing - I only put it in because the images I was given for this particular scenario are 128x128 but only use about 64x64. So I just did what I needed to for my scenario - I’m not trying to make something that is publicly useful yet. :slight_smile:

Thanks for the kiss, Cas. :-*

:wink:
Eli

Sounds about par for software development.

A kiss makes it all better :wink:
You should go indie! Work for yourself.

Cas :slight_smile:

Yeah, maybe in a few years. I’ve still got a lot to learn and a lot of networking (the meeting people kind) to do, then perhaps I will. But I am indeed convinced of the fact that I had more fun (at least in many ways) as a hobbyist. But being indie is hard hard hard, as you can no doubt attest to.

Z-Buffer, sir!
Except that won’t work with transparency…
Oh, ok, depth peeling!

Blah nevermind. :wink:

Hee, I went through both those steps trying to get this working. I ended up basically sorting things by like groups and Y position both, so pretty much there are 5 different groups or so and everything within those groups is sorted by Y. Typically, each group only uses one sprite atlas, maybe two, so the occasional visual height problems usually look decent enough (given that the things are different types of units) that it’s typically acceptable.