Lemmings Sprite format

Started by 0xdeadbeef, August 05, 2005, 10:51:12 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

0xdeadbeef

Is there any information available about the "SPR" files used in Lemmings for Windows?

The files start with the String "SRLE", followed by a 16bit number storing the number of animation frames.
This section is followed by 12 bytes which is followed by the byte-Array containing the animation frames one after the other.

However, I can't seem to figure out what these 12 bytes contain. Neither the correct width nor the height of the sprite array seems to be defined there correctly.
Sometimes values are close, but not correct.

Any ideas???

Mindless

Are you sure all 16 bits are for the number of animation frames, since most animations have less than 4 bits worth of frames.

0xdeadbeef

I would think so, since this looks like a 16bit value in little endian format.
E.g. for "ICO_MINS.SPR" which is the "Minus" icon with only one animation phase, the 14 bytes following "SRLE" look like this:
01 00 0A 00 00 00 03 00 11 00 1B 00 0B 00
which I would read as
0100 0A00 0000 0300 1100 1B00 0B00
or in correct byte order:
0001 000A 0000 0003 0011 001B 000B

As far as I can see, the icon's height should be 11 (0x0b) pixels, while the width should be 28 pixels (0x1c).
The following bytefield of 308 bytes (28*11) seems to represent a minus icon, so I'm fine with that.

However, while there is a 0x0B in the "header", there is no "0x1C", only a "0x1B". This made me wonder, if width and height are stored decreased by one (0x0A and 0x1B).

Then again, the "plus"-Icon ("ICO_PLUS.SPR") looks completely different. The width is obviously the same (28 pixels), but I can't figure out the correct height, which could be something between 17 and 19 (nothing close to this can be found in the header by the way). Also there seems to be additional data after the byte array.

I'm beginning to think that my idea of a byte array might be wrong. Maybe the image data is stored is stored line by line with a "end of line" spearator (probably 0x80) and some additional information inbetween.

I'm kind of confused and would appreciate any fresh ideas here...


the guest

No time or interest to help now, but I'd suggest changing a few bytes and see what happens.  You're not going to get very far by just staring at the bytes.

For example, take the minus icon and try it.  You said you think the 28x11 bytes following the header are the pixels, but you really don't know until you hack the bytes and see what happens.  Or try changing the 2 bytes you think represents the width and height, and see whether it has the expected effects.

Of course, this does kind of assumes that the game doesn't do some kind of checksumming process or the like to see if the bytes are altered, but it's still worth trying.

Mindless

Quote from: 0xdeadbeef  link=1123282272/0#2 date=1123325900I'm beginning to think that my idea of a byte array might be wrong. Maybe the image data is stored is stored line by line with a "end of line" spearator (probably 0x80) and some additional information inbetween.

I'm kind of confused and would appreciate any fresh ideas here...
The byte after the eol (confirmed to be 0x80) is the x offset of "transparent" pixels. Following this is another byte (I don't know what this is) next comes the stream of bytes (1 per pixel) until the next 0x80

I believe the file header spans 0x00 to 0x15.

0xdeadbeef

Hm, in the mean time I figured out some things myself.
The 4 words before the image data are the maximum width and height of the image data and (probably) the width and height of the whole image to be produced, including transparent padding pixels. Probably the two words in front of that are the x and y offset of the stored image inside the transparent target image.

The image data is stored line by line and has the following format:
[x offset] (0x80+len) ... len bytes ... (0x80)
The x offset can be omitted - then it's most probably 0. Obviously it can't be larger than 0x7f, since then it could not be distinguished from the start of line character, which includes the length of the line (0x80 + len).
This also means that a line can't be larger than 0x7f since else it wouldn't fit into a byte.

E.g. the line
0x84 0xAA 0xBB 0xCC 0xDD 0x80
represents four bytes image data (AA,BB,CC,DD) starting at offset 0.

0x03 0x85 0xAA 0xBB 0xCC 0xDD 0xEE 0x80
represents 5 bytes image data (AA,BB,CC,DD,EE) starting at offset 3.

So each line can have a different length, but (excluding start and stop byte) must not exceed the maximum width given in the header (probably for memory allocation issues). The height given in the header equals the number of lines.

If there is more than one animation frame, there is a frame header of 6 words after the image data of the last animation and the image data of the next one. The 6 words are probably x and y offset, maximum width and height of image data stored and width and height of target image.

Between the file header ("SRLE", numberOfFrames) and the first frame header a number of bytes is stored - maybe information for frame grouping or something.
However, I noticed that the 2nd word after "SRLE" is the offset to the first frame's header (relative to the start of the file).
So the file header is:

"SRLE" (numberOfFrames) (firstFrameOffset) ....

Where frames and offset are stored as 16 bit words in little endian format.

And yes, I figured it out by just staring at the bytes ;)

Guess I will write a little tool to show the animation frames and store them into a GIF or something.

Mindless

dang it...
you beat me to it... i only had half of that figured out tho...

0xdeadbeef

Hm, while the stuff written above is basically correct, I found a bunch of other special rules. E.g. a data line might consist of several sub lines:
05 84 30 2C 2C 2C ## 02 84 30 30 2C 2C 80
At the (virtual) position "##", no 0x80 is found: this means, the line is continued after the following offset (0x02). Only if a 0x80 is found after the end of a (sub) line, the line is finished.

Also empty lines are defined (start = 0x80, no end character):
80

Furthermore the large tile sets have an additional line offset: if the start character is 0x7f, which whould normally just be an offset of 0x7f, there is always (?) a 2nd byte which is added to the first one:
7F 0B 94 1A 0B 18 ...
The offset here is not 0x7f, but 0x7f+0x0b, the following 0x94 is the start character for a data line of 0x14 elements.

Today I've written a small java app which can load palettes and sprites. I can load all (?) of the style sprites and most of the gfx sprites. However I still have troubles with ES.SPR and FE.SPR. The "blink" sprites don't seem to contain anything sensible.
Last but not least I seem to miss correct palettes for the icon sprites (ICO_xxx.spr) and the object sprites (e.g. BRICKOS.SPR etc.).

Hm, I would have hoped, this was a bit less tricky :(

0xdeadbeef

Ok, one last note:
The extended offsets marked by 0x7f can be appended multiple times. E.g.
7f 7f 7f 11
means 0x7f + 0x7f + 0x7f + 0x11

With this last change, I could read all the SPR files. Still, I had to figure out how to get the palette for the object (opening trap door, gates etc.):

The object files rely on the according style palette to be loaded with a higher index.
E.g. I hacked BUBBLE.PAL by copying the 0x40 32bit entries and appending them to the palette three times. Then I patched the number of entries from 0x40 to 0x100 (this is the first word after the header " LAP").
With this patched palette, the object file "BUBBLEOB.SPR" looks perfectly right. Maybe I'll implement some feature in my sprite converter to do this palette patching semi-automatic.

the guest

I'm confused, aren't the graphics already displayed correctly in the game, as is?  So what's with this patching of the palette?  :???:

0xdeadbeef

My efforts at the moment are not towards patching the game but to extract graphics - maybe to do a remake in Java or maybe just for fun.
It's just that certain SPR files which containg doors etc. use palette indices which are not existing in the according palette. Obviously the game loads these palettes to a higher index location - most likely 0x80.
So I thought after revelaing all of the SPR format secrets, this might be of some interest to folks who want to extract graphics as well.
If not - yeah well ;)

the guest

Oh ok, so you aren't really patching anything.  You're just trying to figure out how to get the palette work. (and it sounds like you got it figured out, I think?)

0xdeadbeef

I was trying to figure out how to rip all of the graphics.
The palette issue was only the last thing to clarify...

And yes, I succeeded :)