3 This document describes the LBX image format used in Moo2. The goal is that
4 the code to decode images in liblbx can be written against this specification,
5 thus guiding the implementation.
7 All multi-byte integer types are stored in the image file from
8 least-significant to most-significant byte. This document uses the names
9 "uint8", "uint16" and "uint32" to refer to 8-bit, 16-bit and 32-bit unsigned
10 integers, respectively.
12 LBX Images begin with a 12-byte header which has the following layout:
14 OFFSET TYPE DESCRIPTION
15 -----------------------------------------------------
16 0 uint16 Image width in pixels
17 2 uint16 Image height in pixels
18 4 uint16 Unknown (always 0?)
19 6 uint8 Number of frames
20 7 uint8 Unknown (always 0?)
21 8 uint8 Lead-in (less than the frame count)
25 Immediately following the header is an sequence of uint32 offsets (one for
26 each frame) indicating the start of each frame, followed by a final uint32
27 offset which marks the end of the file.
29 The frame count, lead-in and chunk size describe how the image is animated,
30 which is described later. The flags value is the bitwise-OR of zero or more
31 of the following values:
33 VALUE NAME DESCRIPTION
34 ----------------------------------------------------------------------------
35 0x0100 raw If set, this flag enables a simpler method of storing
36 frame data in the image.
37 0x0400 overwrite If set, behave as if the chunk size was 1 instead of its
39 0x0800 building Unknown. This flag is set on the building images
40 (perhaps to enable a special blending mode for shadows).
41 0x1000 palette If set, the image contains embedded palette data.
42 0x2000 loop If set, behave as if the lead-in was 0 instead of its
45 If the palette flag is set, the palette data follows the frame offsets. The
46 palette has a 4-byte header:
48 OFFSET TYPE DESCRIPTION
49 -----------------------------------------------------
50 0 uint16 Index of the first embedded palette entry
51 2 uint16 Number of embedded palette entries.
53 The sum of these two values must not exceed 256. Immediately following the
54 palette header are the palette entries. Each palette entry is 4 bytes with
57 OFFSET TYPE DESCRIPTION
58 -----------------------------------------------------
60 1 uint8 Red component (0-63)
61 2 uint8 Green component (0-63)
62 3 uint8 Blue component (0-63)
64 Note that component values are stored as an 8-bit integer but only range
65 from 0-63 (6 bits per channel), with (0, 0, 0) being the darkest black and
66 (63, 63, 63) the brightest white. The values in the image's embedded palette
67 supersede the values in the "main" palette.
71 Each LBX image consists of one or more frames. The start of each frame
72 can be found by seeking to the appropriate offset in the file, as described
75 There are two main methods of encoding frame data. The simplest is the raw
76 encoding, which is used when the "raw" flag (0x0100) is set in the header.
77 In raw encoding, the pixel data for the entire frame is stored verbatim in
78 row-major order (one uint8 value per pixel). There are no headers to parse
79 within the frame, and this format does not support transparency as each frame
80 specifies a palette index for every pixel in the image.
82 For example, a 3x2 raw image has exactly 6 bytes per frame, with the pixels
83 laid out as in the following format. The numbers represent byte offsets
92 The more common method is a line-based encoding, which is more flexible.
93 In this format, a cursor is maintained to track where pixel data is to be
94 written. The X value of the cursor specifies the number of pixels right
95 from the left edge of the image, and the Y value of the cursor specifies
96 the number of pixels down from the top edge of the image.
98 Each frame in this encoding begins with a header.
100 OFFSET TYPE DESCRIPTION
101 -----------------------------------------------------
103 2 uint16 Initial Y position of cursor.
105 The cursor has an initial X value of 0. Immediately following the header
106 is a sequence of one or more drawing commands. Each command consists of a
109 OFFSET TYPE DESCRIPTION
110 -----------------------------------------------------
111 0 uint16 Length: number of pixels to follow
112 2 uint16 Cursor offset
114 If length is non-zero, first the offset is added to the current X value of the
115 cursor, then the pixel data (1 byte per pixel) follows and is drawn starting
116 at the current cursor position, with successive pixels increasing in X value.
117 The cursor is updated as pixels are drawn. In general, new pixel data
118 supersedes any previous value for a particular pixel. Pixels that have no
119 data specified are transparent. Animated images may re-use pixel values from
120 the previous frame, see below for details.
122 If length is odd, there is a padding byte after the last pixel which must be
125 If length is 0, then the offset is added to the Y value of the cursor, the X
126 value of the cursor is reset to 0, and no pixel data follows.
128 Notwithstanding the above, if both length is 0 and offset is exactly 1000,
129 then there are no further drawing commands in this frame.
133 There are 3 parameters relevant to animations found in the image header: the
134 frame count, the lead-in, and the chunk size. Frame count specifies the total
135 number of frames in the image, chunk size affects how frames are decoded and
136 the lead-in affects how animations are displayed.
138 Normally, each decoded frame is drawn on top of the previous frame, with the
139 first frame drawn on a fully transparent slate. So if the first frame has any
140 unspecified pixel values, those pixels are transparent, while if the second
141 frame has any unspecified pixel values, those pixels retain the value from the
142 first frame (transparent or otherwise).
144 However, if the chunk size is set to a non-zero value, then the slate is reset
145 to a fully transparent state when decoding a frame number which is divisible
146 by the chunk size. So if this is set to 1, every frame must specify all
147 non-transparent pixels as they will each be drawn on top of a transparent
148 slate (just like the first frame). This parameter is the only way for pixels
149 which are opaque in one frame to become transparent in the next.
151 The lead-in specifies the frame to be displayed after the last frame in an
152 animation. If this is different from the last frame, then the result is a
153 looping animation. If this is the same as the last frame, then the result is
154 an animation that stops at the end.