ScummVM logo Main website - Forums - BuildBot - Doxygen - Planet
Contact us - Buy Supported Games: GOG.com
Log in curved edge

SCUMM/Technical Reference/Image resourcesSCUMM/Technical Reference/Image resources

The scumm engines use loads of different image format. Most of them use some bitpacked format with a more or less clever compression. The following is currently limited to the format used for version 6 and above.

LucasHacks! have an intersting article about this at http://scumm.mixnmojo.com/?page=articles/article1 (it is down as of this writing).

SMAP

A smap contain a picture. This used for the background of the rooms and the objects. The coding is quiet strange but for that it is probably efficient on old crappy hardware :) The picture in encoded in vertical stripes of 8 pixels width. The data start with an offset table followed by each encoded stripe. It seems that the overall size of the smap is rounded to the next multiple of 2. Note that no information about the image size is present in the SMAP, this is found in the room or object header.

SMAP v6

  offset table : width/8 elements. Offset are relative to the start of the
                 SMAP block (-8 offset)
    offset     : 32le
    ....
  stripe
    header     : 8
    data

The stripe header is a bit strange. The lower bits are used to store the coding shift. This can be retrieved with a simple header % 10, the rest of the bits code the encoder type used for the stripe. In dott 4 type of encoding are used, i kept the name used in ScummVM (and added one): unkA, unkA6, unkB and unkC :) unkA and unkA6 can both be decoded by the unkA decoder.

SMAP v8

TODO

SMAP Codecs

UnkA
  • Opaque id: 10
  • Transparent id: 12

Decoder

  uint8_t color = read_bits(csh);
  uint8_t inc = 0,n;

  write_pixel(color,1);

  while(pixel_left) {
  
    n = 1;

    if(read_bit()) {
      if(!read_bit()) color = read_bits(csh);
  
      else {
        inc = (read_bits(3) - 4);

        if(inc) color += inc;
        else n = read_bits(8);
      }
    }
  
    write_pixel(color,n);
  }
UnkA6
  • Opaque id: 6
  • Transparent id: 8

A simplified version of the above algorithm. Probably a predecessor. Dunno why some of the images in dott are encoded with this inferior algorithm. Perhaps because it's a bit faster to decode :)

Decoder

  uint8_t color = read_bits(csh);
  uint8_t inc = 0;

  while(pixel_left) {

    write_pixel(color,1);

    if(read_bit()) {
      if(!read_bit()) color = read_bits(csh);
      else color += (read_bits(3) - 4);
    }
  }
UnkB
  • Opaque id: 2
  • Transparent id: 4

Decoder

  uint8_t color = read_bits(csh);
  uint8_t inc = -1;

  while(pixel_left) {

    write_pixel(color,1);

    if(read_bit()) {
      if(!read_bit()) {
        color = read_bits(csh);
        inc = -1;
      } else {
        if(read_bit()) inc = -inc;
        color += inc;
      }
    }
  }
UnkC
  • Opaque id: 1
  • Transparent id: 3

This is the same as unkB except that it is coded by column instead of by line.

ZPnn

ZP0n v6

The encoding is very similar to the SMAP. Again we have an offset table followed by the encoded data. However the offset are only 16 bits width and the special offset of 0 is used to code a stripe full of 0. But the LEC interpreter react strangely to these strides.

 offset table : width/8 elements. Offset are relative to the start of the
                ZPnn block (-8 offset)
   offset: 16le
   ....
 stripe
   data

Decoder

The z plane decode to a bit packed 1 bit per pixel image. The decoder decode a single stripe. As these are 8 pixels in width every line is a single byte. So this time the encoding is byte based that's a lot simpler :)

  uint8_t b,count;

  while(line_left) {

    count = read_byte();

    if(count & 0x80) { // write the same byte count times
 
      count &= 0x7F;
      b = read_byte();

      do {
        write_byte(b);
        count--;
      } while(count && line_left);

    } else {  // write count bytes as is from the input

      do {
        write_byte(read_byte());
        count--;
      } while(count && line_left);

    }
  }

ZPLN v8

TODO

BOMP

The blast object images, these start in v6 with S&M afaik. The encoding is pretty straight forward, it's a simple line by line RLE encoding.

The header is quiet simple and very similar in v6 and v8, only v8 use 32 bits as usual.

BOMP v6

  unk     : 16
  width   : 16le
  height  : 16le
  padding : 2*16
  data    : the encoded image

BOMP v8

  width   : 32le
  height  : 32le
  data    : the encoded image

Codec

Each line start with a 16le storing the size of the encoded line (without the size header itself) followed by the RLE data.

  lines
    encoded size : 16le
    line data    : size bytes

Decoder

Note that this code only decode a single line.

  uint8_t b,count;

  while(len > 0) {
    b = read_byte();

    count = (b >> 1) + 1;
    if(count > len) count = len;

    if(b & 1)
      write_pixel(read_byte(),count);
    else {
      while(count > 0) {
        write_pixel(read_byte(),1);
        count--;
      }
    }

    len -= count;
  }

 

curved edge   curved edge