Difference between revisions of "SCUMM/Technical Reference/Costume resources"
Jestar jokin (talk | contribs) (Copy information from ScummC wiki by Alban Bedel, from archive here: http://wiki.github.com/jamesu/scummc/scumm-costume-formats) |
(No difference)
|
Latest revision as of 01:30, 3 September 2010
Costume formats
1. COST
Costumes store the animations used for characters in the game. The format is relatively complex. It basically consists of a bunch of frames and commands to make use of them :) I had a hard time really figuring out how this works.
size : 32le can be 0 (see num anim) or the size (sometimes with an offset of one ??) header : 2*8 always contain "CO" num anim : 8 if(size) num_anim++ format : 8 bit 7 set means that west anims must NOT be mirrored, bit 0 is the palette size (0: 16 colors, 1: 32 colors) palette : 8*num colors coded in format anim cmds offset : 16le access the anim cmds array limbs offset : 16*16le access limb picture table anim offsets : 16le*num anim access anim definitions anim limb mask : 16le anim definitions : variable length, one definition for each bit set to 1 in the limb mask. 0xFFFF : 16le disabled limb code OR start : 16le noloop : 1 end offset : 7 offset of the last frame, or len-1 anim cmds cmd : 8 limbs pict offset : 16le picts width : 16le height : 16le rel_x : s16le rel_y : s16le move_x : s16le move_y : s16le redir_limb : 8 only present if((format & 0x7E) == 0x60) redir_pict : 8 only present if((format & 0x7E) == 0x60) rle data
Each animation can have up to 16 limbs, each with its own sequence of pictures. The sequences are defined in the anim block. A definition starts with a 16le mask telling which limbs are used. Each bit of the mask stands for a limb. After the mask is a 16le index, giving the start position of the sequence in the anim cmds array. An index of 0xFFFF is used to turn off the limb; if the index is not 0xFFFF, then it's followed by the length of the sequence (8 bits). The highest bit of the length is used to indicate whether the sequence should loop, if it is set the animation doesn't loop.
So an animation is defined by a part of the anim cmds array. This array contains either picture numbers or some special values used to fire sounds, etc. Now to access the pictures, one has to look in the limb table. The table again contains offsets which finally allow us to find the right picture. So each limb has its own set of pictures, although sometimes several limbs share the same table.
As you can see, the format 0x60 has 2 extra fields in the picture header. If they are not 0xFF, they indicate a redirection to the picture redir_pict of the limb redir_limb. Also note that sometimes several entries in the limb table will point to the same picture.
It seems the data is always properly ordered. That is, the first picture of the first limb comes right after the last limb table. The first limb table start right after the cmd array, and so on. Currently this seems to be the only way to determine how long the cmd array is, or how long the last limb table is. Clumsy but it works, however a simple decoder doesn't need to compute these lengths :)
Note: All the offsets are relative to the block start (without the standard 8 byte SCUMM block header).
WARNING: When one numbers the limbs from their corresponding bit in the limb masks, they are then indexed in reverse order. This means the first entry in the limb table is limb 15, then comes limb 14, etc. The same holds for the anim definitions. Rendering should also be done in that order.
Note 2: The transparent color is always 0.
1.2 Commands
There are very few commands available and they have no arguments.
- 0x71-0x78: addSound()
In Lucas games add sound cmd-0x71, in Humongous games add sound 0x78-cmd.
- 0x79: stop()
- 0x7A: start()
- 0x7B: hide()
- 0x7C: skipFrame()
1.3 RLE compression
The compression used for the costume data is a simple byte based RLE compression. However, it works by columns, not by lines. Each byte contains the color in the high bits and the repetition count in the low bits. If the repetition count is 0, then the next byte contains the actual repetition count. How many bits are used for the color depends on the palette size: for a 16 color palette, 4 bits are used for the color; for 32 colors, 5 bits are used.
if(palette_size == 16) { shift = 4; mask = 0xF; } else { shift = 3; mask = 0x7; } while(1) { rep = read_byte(); color = rep >> shift; rep &= mask; if(!rep) rep = read_byte(); while(rep > 0) { set_pixel(x,y,color); rep--; y++; if(y >= height) { y = 0; x++; if(x >= width) break; } } }
1.4 Animations
Costume animations are always grouped in blocks of 4, one for each direction. The four directions are:
- 0: WEST (or right)
- 1: EAST (or left)
- 2: SOUTH (or down)
- 3: NORTH (or up)
Costumes used for normal actors have some predefined animations:
- 00-03: unknown
- 04-07: init
- 08-11: walk
- 12-15: stand
- 16-19: talk start
- 20-23: talk stop
ScummVM maps the following animations:
- 56: init frame (04)
- 57: walk frame (08)
- 58: stand frame (12)
- 59: talk start frame (16)
- 60: talk stop frame (20)
There is also an assert preventing 62 (0x3E), but I really have no clue why.
When actor animations are selected these have a special effect:
- 244-247: turn to new direction
- 248-251: change direction immediately
- 252-255: stop walking
So as far as I can tell, this leaves the ranges 24-55, 64-112 and perhaps 125-243 free for other animations. In DOTT, Hoaggi's costume uses the following:
- 32-35: pick something up raising the arm
- 36-39: pick something up in front
- 40-43: pick something up off the ground
- 44-47: smile
2. AKOS
AKOS, which are used in SCUMM 7 and 8, are much more powerful than the old COST and their data structure seems much cleaner. Could it be worst than the COST ? ;)
Note: some of this come from "LucasHacks":http://scumm.mixnmojo.com/!
2.1 Structure
An AKOS block is made of some block unlike the COST.
- AKHD: Header
- AKPL: Palette (optional)
- RGBS: RGB Values (optional)
- AKSQ: Commands sequence
- AKCH: Anim offset table and definitions
- AKOF: Offset table
- AKCI: Frames definition
- AKCD: Frames data
I found these in the code but not in comi, so i suppose it's only used by he engines.
- AKCT: Condition table ???
- AKST: Sequence table (set seq3, apparenly only used by he games) ???
- AKSF: Sequence table (set seq1 and seq2, apparenly only used by he games) ???
- AKFO: Sequence jump table, 16 bits list
2.2 Blocks content
2.2.1 AKHD
unk1 : 16 flags : 8 unk2 : 8 num anims : 16le num frames : 16le codec : 16le
Flags: bit 0 is mirror, bit 1 is the number of directions the costume have (4 or 8)
2.2.2 AKPL
AKPL blocks are just a list of 8 bits values.
2.2.3 RGBS
RGBS blocks are just a list of 8 bits triplet coding colors.
2.2.4 AKOF
frames AKCD offset : 32le AKCI offset : 16le
2.2.5 AKCI
frames width : 16le height : 16le rel_x : s16le rel_y : s16le move_x : s16le move_y : s16le
2.2.6 AKCD
Just all the commpressed frames packed together.
2.2.7 AKCH
The AKCH block define the various animations, they are pretty similar to the anim definitions in the COST. It start with an offset table giving access to all entries, followed by all definitions. The definitions start with a mask indicating which limb are active, followed by the actual limb definitions.
offset table : num anims time offset : 16le definitions : num anims time limb mask : 16le mode : 8 start : 16le len : 16le
The start and end are there only if mode is not equal to 1, 4 or 5.
mode
- 0: Disabled
- 1: Single frame, no commands ???
- 2: Loop
- 3: Play once
- 4: Stop limb
- 5: Start limb
- 6: Ignore first commande/pic mode ?
- 7: Unk
- 8: Same as mode 6 ?
2.2.8 AKSQ
In AKOS the picture index are mixed with the commands like in the COST, they are found in the AKSQ block. The AKOS have a lot more commands than the old COST so the stream is a mix of 8 and 16 bits values. It is read with something like this:
code = p[0]; if(code & 0x80) code = (code << 8) | p[1];
8 bits values are always picture index. All 16 bits value with 0xC0 in the MSB are commands, the rest are picture index to which a mask of 0xFFF is applied.
2.3 Commands
- 0xC001: return()
- 0xC010: setVar(word value,byte *var)
- 0xC015: startSound(byte snd)
- 0xC016: ifVarSoundIsRunning(uword jmp,byte *snd)
- 0xC017: ifVarSoundIsNotRunning(uword jmp,byte *snd)
- 0xC018: ifSoundIsRunning(uword jmp,byte snd)
- 0xC019: ifSoundIsNotRunning(uword jmp,byte snd)
- 0xC020: complexChan(word ???,byte ???)
Use an alternative rendering mode, apparently it render the limb several time, moving it betwen each frame.
- 0xC021: ???(byte narg,...)
load seq3Idx with the list and switch to complexChan limb rendering
- 0xC022: ???(byte narg,...)
load seq3Idx with the list and switch to complexChan2 limb rendering
- 0xC025: complexChan2(word ???,word ????)
Similar to complexChan but with a subtile difference, which ??
- 0xC030: jump(uword jmp)
- 0xC031: jumpIfSet(uword jmp,byte *var)
- 0xC040: addVar(word val,byte *var)
- 0xC042: startSound(byte snd)
- 0xC044: startVarSound(byte *snd)
- 0xC045: setUserCondition(byte narg,byte slot,byte *set)
- 0xC046: isUserConditionSet(byte narg,byte slot,byte *ret)
- 0xC047: setTalkCondition(byte narg,byte slot)
- 0xC048: isTalkConditionSet(byte narg,byte slot,byte *ret)
- 0xC050: ignore()
- 0xC060: incVar0()
- 0xC061: startSound0()
- 0xC070: jumpE(uword jmp,byte *a, word b)
- 0xC071: jumpNE(uword jmp,byte *a, word b)
- 0xC072: jumpL(uword jmp,byte *a, word b)
- 0xC073: jumpLE(uword jmp,byte *a, word b)
- 0xC074: jumpG(uword jmp,byte *a, word b)
- 0xC075: jumpGE(uword jmp,byte *a, word b)
- 0xC080: startAnim(byte anim)
- 0xC081: startVarAnim(byte *anim)
- 0xC082: random(word min,word max,byte *ret)
- 0xC083: setActorClip(byte val)
- 0xC084: startAnimInActor(byte *actor,byte *anim)
- 0xC085: setVarInActor(byte *actor,byte *var,word val)
- 0xC086: hideActor()
- 0xC087: setDrawOffs(word a,word b)
- 0xC088: jumpTable(byte *entry)
- 0xC089: soundStuff(byte snd,byte ???,byte cmd,byte ???,byte val)
- 0xC08A: flip(word val)
- 0xC08B: cmd3(byte ???,byte ???, byte ???, byte ???)
- 0xC08C: ignore3(byte ???)
- 0xC08D: ignore2(byte ???)
- 0xC08E: resetVolume(word snd)
- 0xC090: skipE(word a, byte *b)
- 0xC091: skipNE(word a, byte *b)
- 0xC092: skipL(word a, byte *b)
- 0xC093: skipLE(word a, byte *b)
- 0xC094: skipG(word a, byte *b)
- 0xC095: skipGE(word a, byte *b)
- 0xC09F: clearFlag()
- 0xC0A0: resetPan(byte snd,byte ???)
- 0xC0A1: jumpIfTalking(uword jmp)
- 0xC0A2: jumpIfNotTalking(uword jmp)
- 0xC0A3: resetVarPan(byte *snd)
- 0xC0A4: ???
- 0xC0A5: ???
- 0xC0A6: ???
- 0xC0A7: ???
- 0xC0FF: enqSeq
2.4 Codecs
There are 4 known codec: 1, 5, 16 and 32. The latter is only supported by HE engines.
2.4.1 Codec 1
This codec seems identical to the one used in the old COST, except it also support 64 colors. I suppose it's not very efficient in 64 colors mode as any repeat of more than 3 will need 2 bytes.
2.4.2 Codec 5
This one use the same encoding as BMOP image. See Scumm Image formats.
2.4.3 Codec 16
bpp = read_byte(); color = read_byte(); repeat = 0; while(pos < width*height) { write_pixel(pos%width,pos/width,color); if(repeat > 0) repeat--; else if(read_bit()) { if(read_bit()) { delta = read_bits(3); if(delta != 4) color += delta-4; else repeat = read_bits(8) - 1; } else color = read_bits(bpp); } pos++; }