Cosmo Tileinfo Format
The Cosmo Tileinfo Format is the data format used by Cosmo's Cosmic Adventures to store the layout of the actor tiles - where each 8×8 tile should be drawn to produce a creature on-screen, how many frames the creature has, etc. A newer version of this format was later used by Duke Nukem II.
There is no known way of detecting this file format, beyond recognising the filename and the presence of the image data file. The usual methods, such as scanning the offsets and verifying they are within range, could be used to assist with autodetection.
The format consists of a list of offsets for each actor, with a number of frames at each offset.
|UINT16LE[...]||actorOffset||Offset in words (units of 2-bytes) from the start of the file to the actor structure (see below)|
Since the count is not stored in the file, the only way to read in all the actor offsets is to keep reading until the offset of the first structure is reached (alternatively since the offsets are in words and the offsets are each a word long, the first offset is also the number of offsets/actor structures.)
At each actorOffset, the actor structure is:
|UINT16LE||height||Height of frame, in tiles|
|UINT16LE||width||Width of frame, in tiles|
|UINT32LE||frameOffset||Offset into tileset file, in bytes, for frame image. One byte too many every 64k (see below.)|
This structure is repeated until the offset of the next actor is reached. The only way to calculate how many frames a specific actor occupies would be to find the difference between its offset and the following offset (or the file size, if it's the last offset) and divide the result by four (the size of the actor structure.)
Graphics data is stored in blocks in memory with a maximum size of 65535 bytes ($FFFF), and no actor frame can span two blocks. This has important consequences, namely that the there is padding data in the tileset. If there is not enough space in one block for an actor frame then the block will be filled with padding and the actor frame will be placed at the start of the next block.
Since blocks are one byte less than 64K, but the addresses of blocks are multiples of 64K there is a one byte discrepancy per block. That is, the frameOffset figure contains one too many bytes in every 64k block - i.e. if the offset is 65536, you only seek to 65535. If the offset is 131072 you only seek to 131070. A simple formula for this is finalOffset = frameOffset - (frameOffset / 65536).
This applies only to ACTORS.MNI. Being a 16-bit DOS program, Cosmo cannot allocate and use buffers larger than 65535 bytes without being forced to use HUGE pointer arithmetics, which are usually a lot slower than regular pointers. To avoid this, the game allocates 3 buffers for the contents of ACTORS.MNI: the first two buffers are each 65535 bytes (0xFFFF) in size and the size of the third is based on the size of ACTORS.MNI. The contents are loaded into these buffers (the first 65535 bytes into buffer 0, the next 65535 bytes into buffer 1 and the remaining bytes into buffer 2). The frameOffset is actually interpreted as two UINT16LE values. The first value (low 16 bits of the UINT32LE) stores the offset into the buffer, while the second UINT16LE (high 16 bits of the UINT32LE) stores the index of the buffer to use.
This file format was reverse engineered by Malvineous. Szevvy figured out how the 65535 offset works and Levellass figured out why. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)