]> git.draconx.ca Git - liblbx.git/blobdiff - doc/txt/image-format.txt
lbximg: Fix wart in frame scanline header format
[liblbx.git] / doc / txt / image-format.txt
diff --git a/doc/txt/image-format.txt b/doc/txt/image-format.txt
new file mode 100644 (file)
index 0000000..0a558dd
--- /dev/null
@@ -0,0 +1,154 @@
+LBX Images:
+
+This document describes the LBX image format used in Moo2.  The goal is that
+the code to decode images in liblbx can be written against this specification,
+thus guiding the implementation.
+
+All multi-byte integer types are stored in the image file from
+least-significant to most-significant byte.  This document uses the names
+"uint8", "uint16" and "uint32" to refer to 8-bit, 16-bit and 32-bit unsigned
+integers, respectively.
+
+LBX Images begin with a 12-byte header which has the following layout:
+
+  OFFSET   TYPE     DESCRIPTION
+  -----------------------------------------------------
+       0   uint16   Image width in pixels
+       2   uint16   Image height in pixels
+       4   uint16   Unknown (always 0?)
+       6   uint8    Number of frames
+       7   uint8    Unknown (always 0?)
+       8   uint8    Lead-in (less than the frame count)
+       9   uint8    Chunk size
+      10   uint16   Flags
+
+Immediately following the header is an sequence of uint32 offsets (one for
+each frame) indicating the start of each frame, followed by a final uint32
+offset which marks the end of the file.
+
+The frame count, lead-in and chunk size describe how the image is animated,
+which is described later.  The flags value is the bitwise-OR of zero or more
+of the following values:
+
+  VALUE   NAME        DESCRIPTION
+  ----------------------------------------------------------------------------
+  0x0100  raw         If set, this flag enables a simpler method of storing
+                      frame data in the image.
+  0x0400  overwrite   If set, behave as if the chunk size was 1 instead of its
+                      actual value.
+  0x0800  building    Unknown.  This flag is set on the building images
+                      (perhaps to enable a special blending mode for shadows).
+  0x1000  palette     If set, the image contains embedded palette data.
+  0x2000  loop        If set, behave as if the lead-in was 0 instead of its
+                      actual value.
+
+If the palette flag is set, the palette data follows the frame offsets.  The
+palette has a 4-byte header:
+
+  OFFSET   TYPE     DESCRIPTION
+  -----------------------------------------------------
+       0   uint16   Index of the first embedded palette entry
+       2   uint16   Number of embedded palette entries.
+
+The sum of these two values must not exceed 256.  Immediately following the
+palette header are the palette entries.  Each palette entry is 4 bytes with
+the following layout:
+
+  OFFSET   TYPE     DESCRIPTION
+  -----------------------------------------------------
+       0   uint8    Always 1.
+       1   uint8    Red component   (0-63)
+       2   uint8    Green component (0-63)
+       3   uint8    Blue component  (0-63)
+
+Note that component values are stored as an 8-bit integer but only range
+from 0-63 (6 bits per channel), with (0, 0, 0) being the darkest black and
+(63, 63, 63) the brightest white.  The values in the image's embedded palette
+supersede the values in the "main" palette.
+
+Image data:
+
+Each LBX image consists of one or more frames.  The start of each frame
+can be found by seeking to the appropriate offset in the file, as described
+above.
+
+There are two main methods of encoding frame data.  The simplest is the raw
+encoding, which is used when the "raw" flag (0x0100) is set in the header.
+In raw encoding, the pixel data for the entire frame is stored verbatim in
+row-major order (one uint8 value per pixel).  There are no headers to parse
+within the frame, and this format does not support transparency as each frame
+specifies a palette index for every pixel in the image.
+
+For example, a 3x2 raw image has exactly 6 bytes per frame, with the pixels
+laid out as in the following format.  The numbers represent byte offsets
+within the file:
+
+  +---+---+---+
+  | 0 | 1 | 2 |
+  +---+---+---+
+  | 3 | 4 | 5 |
+  +---+---+---+
+
+The more common method is a line-based encoding, which is more flexible.
+In this format, a cursor is maintained to track where pixel data is to be
+written.  The X value of the cursor specifies the number of pixels right
+from the left edge of the image, and the Y value of the cursor specifies
+the number of pixels down from the top edge of the image.
+
+Each frame in this encoding begins with a header.
+
+  OFFSET   TYPE     DESCRIPTION
+  -----------------------------------------------------
+       0   uint16   Always 1.
+       2   uint16   Initial Y position of cursor.
+
+The cursor has an initial X value of 0.  Immediately following the header
+is a sequence of one or more drawing commands.  Each command consists of a
+2-byte header.
+
+  OFFSET   TYPE     DESCRIPTION
+  -----------------------------------------------------
+       0   uint16   Length: number of pixels to follow
+       2   uint16   Cursor offset
+
+If length is non-zero, first the offset is added to the current X value of the
+cursor, then the pixel data (1 byte per pixel) follows and is drawn starting
+at the current cursor position, with successive pixels increasing in X value.
+The cursor is updated as pixels are drawn.  In general, new pixel data
+supersedes any previous value for a particular pixel.  Pixels that have no
+data specified are transparent.  Animated images may re-use pixel values from
+the previous frame, see below for details.
+
+If length is odd, there is a padding byte after the last pixel which must be
+skipped.
+
+If length is 0, then the offset is added to the Y value of the cursor, the X
+value of the cursor is reset to 0, and no pixel data follows.
+
+Notwithstanding the above, if both length is 0 and offset is exactly 1000,
+then there are no further drawing commands in this frame.
+
+Animation:
+
+There are 3 parameters relevant to animations found in the image header: the
+frame count, the lead-in, and the chunk size.  Frame count specifies the total
+number of frames in the image, chunk size affects how frames are decoded and
+the lead-in affects how animations are displayed.
+
+Normally, each decoded frame is drawn on top of the previous frame, with the
+first frame drawn on a fully transparent slate.  So if the first frame has any
+unspecified pixel values, those pixels are transparent, while if the second
+frame has any unspecified pixel values, those pixels retain the value from the
+first frame (transparent or otherwise).
+
+However, if the chunk size is set to a non-zero value, then the slate is reset
+to a fully transparent state when decoding a frame number which is divisible
+by the chunk size.  So if this is set to 1, every frame must specify all
+non-transparent pixels as they will each be drawn on top of a transparent
+slate (just like the first frame).  This parameter is the only way for pixels
+which are opaque in one frame to become transparent in the next.
+
+The lead-in specifies the frame to be displayed after the last frame in an
+animation.  If this is different from the last frame, then the result is a
+looping animation.  If this is the same as the last frame, then the result is
+an animation that stops at the end.