clintbellanger/flare-game — pull request #1 by stefanbeller (2012-09-18 15:52:02+00:00)
Title: Enemy animations shrinking.

Finally here is the pullrequest for the spritesheetpacking.
This pull request contains 2 commits, the first was manually crafted,
the second was completely automatically generated.

Manually I needed to adapt the enemy definitions, since some animation definition
filenames have changed.
Now the animations file name is equal to the gfx filename nearly everywhere.

The automatically generated commit shrinkes the images and rewrites the
actual animation definition files.

The spritesheetpacker is split up into 2 pieces, one very flare-engine
specific python script to read in animation definition files and images
and extract the rectangles from these two files.
The other part is a generic rectpacker, which is written in C++.

The rectpacker gets the width and heights of the rectangles passed via
commandline and spits out the coordinates of the rectangles on stdout, so that
the rectangles are arranged to fit in the smallest enclosing rectangle possible.

To obtain the spritesheetpacker run
```
git clone https://github.com/stefanbeller/RectangleBinPack.git
cd RectangleBinPack

cd bestEnclosingRect
make
# make puts the compiled binary called 'rectpacker' into ~/bin
# make sure to either adapt the Makefile or add ~/bin to PATH variable.
cd ..
```

The general command to shrink images for flare games is this:
```
cd flare
./spritesheetpacker --definition --images
# This assumes the rectpacker binary in PATH!
```
It is intended to be able to pass multiple animation definition files and
image files at once.
As of writing this, this is not working correctly. So as of now it is suggested
to only pass one of each.
If the frames in the image files have exactly the same boundaries and have
the same renderoffsets, it still works for now.

This pull request was crafted using the script ```start.sh```, which
contains lots of calls to ```./spritesheetpacker``` in that given repository and a
little unix shell magic to create the correct animation definition files.

Specially the goblins, which have different animations within the animation file
needed some care. All frames which are not addressed by the animation definition
will be dropped from the resulting image by ```./spritesheetpacker```, so
first an animation definition containing both the hopping and the running was
created. Afterwards the resulting animation file needed to be split up again
to have one animation file for the hopping goblin and one for the running goblin.

I have not found any error on playtesting so far, please help me with testing before merging.

---
PS: A general note on the sprite sheetpacking:
When trying to minimize the area of a sprite, you need to choose values for the
width and the height, so you have a degree of freedom here.
The rectpacker tries minimizing the area by lowering it iteratively.
(first using a binary search, between a known good and the known optimum,
after the binary search has finished, it starts searching more exhaustive
with a linear area lowering strategy.)

However some hardware (specailly older hardware) can only process images
if these have widthes and heights being a power of two.

So just minimizing the area is not enough, because consider a sprite having the
size of 400 times 1100 being 440k pixels in total. The older hardware would
blow up the image to the next power of two being 512 times 2048 totaling in
1048k pixels.

So maybe it would be smarter to pack the image circa 500 times circa 900,
which is slightly more pixels then the 440k, but on hardware only
supporting power of twos it would be 512 times 1024, which is only half the memory
as the 1048k pixels.

So the general rectpacking strategy is this:
```
- first find the smallest enclosing rectangle having width and height being a power of 2
- set the obtained powers of 2 for width/heights as maximum.
- now start optimizing the total area not exceeding the maximum width/height
```
This strategy doesn't necessarily get the very best result in total area, but in
power of two boundaries. Since this pullrequest only shrinks memory usage, which is
often a problem on older hardware, this might be the right thing(tm)