Skip to content

Latest commit

 

History

History
132 lines (104 loc) · 5.53 KB

File metadata and controls

132 lines (104 loc) · 5.53 KB

07 - Graphics

The CD32 is an AGA machine. Dragonstone barely uses that.

FMODE 0

Lx_DataL.exe writes FMODE ($DFF1FC) with 0. That is the AGA register that selects 16-, 32- or 64-bit bitplane fetches; zero is the OCS/ECS- compatible setting. Before the game has drawn a pixel it has turned the CD32's wider display path off and put the chipset back into the mode an A500 would use.

Nothing else on the disc writes FMODE, BPLCON3, BPLCON4 or the AGA colour-bank registers. This is an ECS-era engine running on AGA hardware with the AGA features switched off -- which is what you would expect from a game that also exists on the Amiga 1200 floppy set and still knows how to ask you to change disks (11-leftovers.md).

Lx_ChipI.cru -- a chip RAM image

202,332 bytes that unpack to a straight image of chip memory, with only three non-empty regions in it:

Offset Length Contents
0x00000 1,536 copper lists
0x0D200 3,072 (bitmap)
0x0F500 25,856 (bitmap)

Everything else -- 87 % of the file -- is zeroes. The loader does not build its screen; it loads a snapshot of one, buffers and all, and points the copper at it.

The copper lists

tools/copper.py disassembles them. There are four, and they document the loader's display exactly:

At 0x0000 and 0x001C -- blanking. BPLCON0 = $0200 (no bitplanes, colour burst on), COLOR00 = $0000, a couple of waits, INTREQ = $8010 to raise the copper interrupt, end.

At 0x0034 -- a three-bitplane strip.

MOVE DIWSTRT , $A471      display window, lines 164..172
MOVE DIWSTOP , $ACD1
MOVE DDFSTRT , $0038      20 lowres fetches = 320 pixels
MOVE DDFSTOP , $00D0
MOVE BPL1MOD , $0050      modulo 80 = (3-1) * 40
MOVE BPL2MOD , $0050
MOVE BPLCON0 , $3200      BPU = 3, eight colours
MOVE SPR0PTH..SPR7PTL     all eight sprites -> $000151A8
MOVE BPL1PTH , $0001      plane 1 -> $00019A8A
MOVE BPL2PTH , $0001      plane 2 -> $00019AB2   (+0x28 = +40)
MOVE BPL3PTH , $0001      plane 3 -> $00019ADA   (+0x28)
WAIT VP=$28
MOVE COLOR00..COLOR07 , $0000

The three bitplane pointers are 40 bytes apart and the modulo is 2 x 40. That is the definitive statement of the disc's bitmap format: interleaved planar, where the rows of the N planes of one scanline sit next to each other and BPLxMOD = (planes - 1) * bytes_per_row. Everything on this disc that is a bitmap is stored that way.

All eight hardware sprites point at the same address, which is the standard way of parking them on a null sprite.

At 0x0234 -- a four-bitplane screen with a real palette.

BPLCON0 = $4200     BPU = 4, sixteen colours
BPLCON2 = $0024
DIWSTRT = $2881 / DIWSTOP = $10B1
BPL1MOD = BPL2MOD = $0030

COLOR00 $0000   COLOR01 $0221   COLOR02 $0443   COLOR03 $0776
COLOR04 $0800   COLOR05 $0A20   COLOR06 $0C40   COLOR07 $0430
COLOR08 $0660   COLOR09 $0880   COLOR10 $0620   COLOR11 $0740
COLOR12 $0962   COLOR13 $0B84   COLOR14 $0CCC   COLOR15 $0110
COLOR16 $0222   COLOR17 $0FFF   COLOR18 $0ED5   COLOR19 $0D93
COLOR20 $0A60   COLOR21 $0840   COLOR22 $0620   COLOR23..31 $0000

Twelve-bit $0RGB values: dark blue-greys, reds, golds and a white -- a parchment palette for the loading panel. Colours 16 to 22 are written even though BPU = 4 only addresses 0 to 15, so the second half of the palette is being staged for something else (a sprite bank, or a later BPLCON0 change).

This list confirms the interleaved format a second time and from different numbers. DDFSTRT = $38 with DDFSTOP = $70 is eight lowres fetches, so 16 bytes per plane row, 128 pixels wide -- and BPLxMOD = $30 = 48 = 3 x 16, again exactly (planes - 1) * bytes_per_row. Two copper lists, two different widths and plane counts, the same rule.

Bitmap geometry

The interleaved format is settled. The block geometry is not, and this is where the documentation stops being certain.

Measuring the row pitch by byte autocorrelation over each file's pixel data gives a clean answer for two of them and no answer for the rest:

File Strongest period Reading
Lx_TPage bitmap region 16 bytes, sharply 32 pixels wide x 4 planes interleaved
Lx_MSprF / Lx_MSprM 128 bytes, then 256 a 128-byte frame or block
L?_GSBlk 4 bytes, decaying smoothly no periodicity above the pixel level
Lx_CompC 40 bytes, weakly 320 pixels wide, one plane

For Lx_TPage the 16-byte peak is unambiguous: the score at 16 is 0.695, at 14 it is 0.491 and at 18 it is 0.495. Rendering that region as 32 x 32 blocks of 4 interleaved planes produces recognisable curves and shading, so the width is right and the block height is not yet pinned down.

The tile banks are the hard case. They are certainly not compressed -- re-compressing the unpacked GSBlk files with zlib gives 0.09 to 0.50, which is what raw pixel art looks like -- but 16 x 16 and 32 x 32 sheets at four and five planes, interleaved and separated, all render as noise. Something between the file offset and the pixels is still missing: a header, a per-block index, or a block size that is not a power of two. See 12-open-questions.md.

Palettes

Only Lx_ChipI carries palettes as copper MOVE COLORxx instructions. The level palettes are not stored that way -- scanning every unpacked file for copper-style COLOR00 writes finds nothing that looks like a 16- or 32-entry table outside Lx_ChipI and a couple of runs in Lx_CompC. The level palettes must live inside GSBlk or LLoad as plain word arrays, which is the other half of the geometry problem.