View Single Post
Neobeo

JCF Member

Joined: Sep 2002

Posts: 409

Neobeo is an asset to this forumNeobeo is an asset to this forum

Apr 2, 2006, 01:48 PM
Neobeo is offline
Reply With Quote
The J2A File Format
Well, it should probably be called the anims.j2a file format, since that's the only file I'm aware of that uses the j2a extension.

The ALIB Header
This is not a C/C++ structure, but I will be using a similar format to define the ALIB header.

Code:
struct ALIB_Header {
	char Magic[4] = "ALIB"; //just an identifier, ignore null-char overflow
	long Unknown = 0x00BEBA00; //little endian, no idea what its for
	long HeaderSize; //Equals 464 bytes for v1.23 anims.j2a
	short Version = 0x0200; //Probably means v2.0
	short Unknown = 0x1808; //no idea what this is
	long FileSize; //Equals 8182764 bytes for v1.23 anims.j2a
	long CRC32; //Note: CRC buffer starts after the end of header
	long SetCount; //Number of sets in the anims.j2a (109 in v1.23)
	long SetAddress[SetCount]; //Each set's starting address within the file
}
Right after the ALIB header, which is not all that confusing, comes the first of many sets. However, to be more technical, we'll call them ANIM sub-files. In addition, these ANIM sub-files each contain 4 sub-sub-files, which are, in order, Animation Info, Frame Info, Image Data, Sample Data. For simplicity, we will think of them as buffers as call them Data1 to Data4.

Each ANIM sub-file starts with a 44-byte header like this:
Code:
struct ANIM_Header {
	char Magic[4] = "ANIM"; //just an identifier, ignore null-char overflow
	unsigned char AnimationCount; //number of animations in set
	unsigned char SampleCount; //number of sound samples in set
	short FrameCount; //total number of frames in set
	long SampleUnknown; //Unknown, but related to the sound samples
	long CData1; //Compressed size of Data1 (Animation Info)
	long UData1; //Uncompressed, remember the zlib tutorial?
	long CData2;
	long UData2;
	long CData3;
	long UData3;
	long CData4;
	long UData4; //lazy all the way up to here
}
After that you should see your familiar zlib stream that starts with "78 DA". As soon as that stream ends the next one begins, until the end of Data4's stream. That's where the next set starts and the next ANIM header appears.

Data1 - Animation Info
Assuming you have already uncompressed this, you will get a buffer of (UData1) bytes, which also happens to be (8 * AnimationCount). This is because each animation info is only 8 bytes long:
Code:
struct AnimInfo {
	short FrameCount; //number of frames for this particular animation
	short FPS; //not really sure what this is, so I'm guessing FPS
	long Reserved; //zeroes, used internally by Jazz2.exe
}
Should be pretty straightforward, no explanation required.

Data2 - Frame Info
Same as above, uncompress, and discover that UData2 = 24 * FrameCount. Each frame info is 24 bytes long:
Code:
struct FrameInfo {
	short Width;
	short Height;
	short ColdspotX; //relative to the hotspot!!
	short ColdspotY; //relative to the hotspot
	short HotspotX; //This is a misnomer. In reality, this is where the
	short HotspotY; //frame starts drawing relative to the "hotspot".
	short GunspotX; //relative to hotspot
	short GunspotY; //...
	long ImageAddress; //Address in Data3 where image starts
	long MaskAddress; //Address in Data3 where mask starts
}
What the relatives mean is that the hotspotx and hotspoty value are almost always negative values, (there are notable exceptions of course). I will try to include an example at the end of everything.

Data3 - Image Data
By now uncompressing it should be a breeze. But how do you use the info contained in here? JJ2 uses its own format (or maybe one that already exists, but I don't recognise), which is similar to RLE. The first four bytes contain width and height, except that the width has some flag that is sometimes set on its most significant bit. I have no idea what that is, so we'll skip it.

After those 4 bytes, try to read the image data as codebytes. A codebyte < 128 (0x80) means to skip that many pixels. A codebyte > 128 (0x80) means to read and set that many pixels from the buffer onto the image. A codebyte = 128 (0x80) means to skip to the next row. Note that the overall image data is aligned to 8 bytes, so there can be up to 7 bytes of unused bytes between the current frame's image data and the next one.

You probably already realised that the image is 8-bits, so get a palette from some random level to start with. Anyway, the mask data is also in this Data3, and is 2-bit (black or white). I have yet to check whether this is clipping mask or transparency mask (more likely the latter), but anyway the mask data is aligned to 4 bytes.

Data4 - Sample Data
I have never been good with sound. In short, I haven't even attempted to find out what could possibly lie in here.

End of anims.j2a
The next post should include an example of reading a single frame in anims.j2a. Unless I'm very lazy or out of time, in which case I'll jump to J2T and J2L.
__________________
<TABLE border=1><TR><TD>Facts:
Jazz Sprite Dynamite (JSD)
Tileset Extractor
Neobeo's Firetruck

</TD><TD>Myths:
Jazz Creation Station Plus (JCS+) - 10%
Coming soon - a dedicated server! - 25%
Jazz Sprite Dynamite v2 (JSDv2) - 2%
Another generic single-player level - 0%
</TD></TR></TABLE>