This is my attempt to describe how the BDP (Block Drawn Pictures) images were stored
in the SAGA games. The information seems to be consistent for both
the Spectrum and the Commodore 64 file formats.
With initial testing programs, pdd and myself have managed to extract the Lion's share of
images.
Example code is also present - note the code evolved as I worked out
different bits of the format. It is in desperate need of a rewrite. But it will render all
images from versions 1 through 3 perfectly. It will render images from version 0 with about 90%
accuracy.
The code is no official licence - all I ask is that if you use any bits of the code, you
acknowledge that this code was written by David Lodge, with help from Paul David Doherty.
There are several versions of the engine used, and differences in the way that they are
rendered, these are:
- Version 0: Incredible Hulk
- A cut down version with no table of pointers and a reduced header, plus character information
is separate from the image data.
- Version 1: Adventureland, Secret Mission, Sorceror of Claymorgue Castle
- The original version, using only 8 colours.
- Version 2: Spiderman
- This adds an extra 8 colours (the Spectrum 'bright' colours).
- Version 3: Savage Island 1 and 2, Gremlins, Supergran
- The lookup table is now relative to memory location. The colours are redefined as octal values.
- Version 4: Robin of Sherwood, Seas of Blood
- There is a slight saving in space where all graphic blocks are not used.
Pictures are now made up of blocks.
- Version 5: Rebel Planet, Temple of Terror, He-Man: Terraquake *
- Further enhancement of Version 4.
- Unknown: Kayleth, The Human Torch and the Thing
* Conjecture, have not managed to render images yet
The graphics data is found immediately following the game data. It is composed of the following
chunks:
0 | Character chunk |
0x800 | Image offsets chunk |
(0x800) | Image #0 data chunk |
| Image #0 colour chunk |
(0x800+MAX) | Image #MAX data chunk |
| Image #MAX colour chunk |
(Where MAX is the total number of images in the file)
Character chunk
In all version this is composed of 256 x 8 bytes for characters. Each byte signifies 8 pixels in
the character, a set bit represents a plotted pixel. This results in a character being a block of 8
x 8 pixels.
Image offsets chunk
Version 1-2: This is a table of offsets to the image. Each offset consists of a 16 bit
number in LSB format. The pointer is a direct link to the memory address of the image.
Version 3+: As Version 1-2, except that the address is relative to the start of the Image
offset chunk.
Image data chunk
First off we have the image header. In Version 0, this is:
unsigned char xsize,
unsigned char ysize
In all other versions this is:
unsigned char xsize,
unsigned char xoffset,
unsigned char ysize,
unsigned char yoffset
Then we have a stream of rendering information. This should by read and rendered byte by byte
until the area covered by xsize and ysize is filled in.
If bit 7 of the byte in unset then the character indexed by that byte should be rendered. (But
see complications below)
If bit 7 is set then this is a command byte, of the following format:
Where:
C = Signifies a command byte
F = Character is flipped along the Y axis
T = Transform of the character
O = Overlay and plot mode (see below)
R = Repeat the stream of data
X = Add 127 to the value of the character
If the R bit is set then the next read byte is a repeat count. Otherwise the next byte is
the character to be rendered.
The Transform bits signify whether any transforms need to be performed on the character:
0 0 = No transforms
0 1 = Rotate character through 90 degrees
1 0 = Rotate character through 180 degrees
1 1 = Rotate character through 270 degrees
The Overlay bits signify that the character should be overlayed by the following stream.
The bits signify how the overlay should be plotted:
0 0 = The new character is plotted
0 1 = The new character is ORed
1 0 = The new character is ANDed
1 1 = The new character is XORed
Note, that the plot mode is for the next character (ie the overlaying character)
not the current one. There may be more than two characters being overlayed.
It is feasible for all bits to be set in a command byte. In the case of Repeat and Overlay
bits being set then the character is plotted n times and then those characters are all overlayed.
Complications
When a character is plotted directly, there is a difference between a normal plot and an
overlay of whether it inherits the X bit. When it is plotted normally it inherits the state of
the X bit, in an overlay it doesn't.
Image colour data chunk
This is a stream of bytes signifying the colours, each block of colours represents one 8 x 8
block of pixels.
If the image is less than Version 3 then bit 7 is a repeat flag if this is clear the values
for the byte are:
Where:
R = Repeat flag
P = Pen colour
B = Brightness flag (not used in versions 0 and 1)
S = Screen colour
If bit 7 is set then this becomes:
Where:
R = Repeat flag
C = Count of repeats
Then the following colour byte is repeated for C + 1 occurences.
If the images is > version 3 bit 7 is still a repeat flag, if unset then the byte is:
Where:
R = Repeat flag
P = Pen colour
B = Brightness flag
S = Screen colour
The only difference when bit 7 is set is that C refers to the previous byte.
Code
The code to render the images is included here for completeness.
Note, this code was (and still is) used to test my theories about rendering the images, with
extra bits (such as the look-up tables and the colour maps) from pdd. It is not
an example of good coding practice and is in severe need of a rewrite!
To command-line format is:
Usage: sagadraw filename game palette
e.g. sagadraw adventureland.sna s1 zxopt
Accepted games: s1, s3, s10, s11, s13, s13c64, q2, q2c64, o1, o2
Accepted palettes: zx, zxopt, c64a, c64b, vga
Images
The extracted images:
Adventureland
|
Secret Mission
|
Savage Island Part 1
|
Savage Island Part 2
|
Sorceror of Claymorgue Castle
|
The Hulk
|
Spider-Man
|
Supergran
|
Gremlins
|
Robin of Sherwood
|
Seas of Blood
|
|