.define vram_ptr $DFC0 ; word: VRAM address
.define buffer $DFD0 ; 32-byte decompression buffer
; hl = dest
; ix = src
decompress:
ld (vram_ptr),hl ; cache VRAM address
ld c,(ix) ; bc = number of tiles
inc ix
ld b,(ix)
inc ix
_DecompressTile:
push bc ; save number of tiles
ld b,$04 ; count 4 bitplanes
ld de,buffer ; write to de
ld c,(ix) ; c = encoding information for 4 bitplanes
inc ix
_DecompressBitplane:
rlc c ; %0x = all bits either 0 or 1
jr nc,_AllTheSame
rlc c ; %11 = raw data
jr c,_RawData
_Compressed:
ld a,(ix) ; get method byte
inc ix
ex de,hl ; get bitplane, if it's referring to one
ld d,a
and $03
add a,a ; calculate address of that bitplane
add a,a ; = buffer + bitplane * 8
add a,a
ld e,a
ld a,d ; get method byte back
ld d,$00
ld iy,buffer
add iy,de ; now iy points to the referred to bitplane
ex de,hl
; now check the method byte
cp $03 ; %000000pp
jr c,_DuplicateBitplane
cp $10
jr c,_CommonValue
cp $13 ; %000100pp
jr c,_DuplicateBitplaneInvert
cp $20
jr c,_CommonValue
cp $23 ; %001000pp
jr c,_DuplicateBitplanePartial
cp $40
jr c,_CommonValue
cp $43 ; %010000pp
jr c,_DuplicateBitplanePartialInvert
; fall through
_CommonValue:
ld h,a ; h = bitmask
ld l,(ix) ; l = common value
inc ix
jr _OutputCommonValue
_RawData:
ld h,$00 ; empty bitmask; no common value
jr _OutputCommonValue
_AllTheSame:
rlc c ; get next bit into carry
sbc a,a ; will make $00 if carry = 0, $ff if it's 1
ld l,a ; that's the common value
ld h,$ff ; full bitmask
; fall through
_OutputCommonValue:
push bc
ld b,8 ; loop counter
-: ld a,l ; get common value
rlc h ; get bit out of bitmask
jr c,+ ; if 1, use the common value
ld a,(ix) ; else get it from (ix++)
inc ix
+: ld (de),a ; write to dest
inc de
djnz - ; loop over 8 bytes
pop bc
jr _BitplaneDone
_DuplicateBitplane:
ld hl,$ff00 ; full copy bitmask, empty inversion bitmask
jr _OutputDuplicate
_DuplicateBitplaneInvert:
ld hl,$ffff ; full copy bitmask, full inversion bitmask
jr _OutputDuplicate
_DuplicateBitplanePartial:
ld h,(ix) ; get copy bitmask
ld l,$00 ; empty inversion bitmask
inc ix
jr _OutputDuplicate
_DuplicateBitplanePartialInvert:
ld h,(ix) ; get copy bitmask
ld l,$ff ; full inversion bitmask
inc ix
; fall through
_OutputDuplicate:
push bc
ld b,8 ; loop counter
-: ld a,(iy) ; read byte to copy
inc iy
xor l ; apply inversion mask
rlc h ; get bit out of bitmask
jr c,+ ; if 1, use the copied value
ld a,(ix) ; else get it from (ix++)
inc ix
+: ld (de),a ; write to dest
inc de
djnz - ; loop over 8 bytes
pop bc
; fall through
_BitplaneDone:
dec b ; decrement bitplane counter
jp nz,_DecompressBitplane ; loop if not zero
_OutputTileToVRAM:
ld hl,(vram_ptr)
call SetVRAMAddressToHL
ld de,$0008 ; we are interleaving every 8th byte
ld c,e ; counter for the interleaving run
ld hl,buffer ; point at data to write
--: ld b,4 ; there are 4 bytes to interleave
push hl
-: ld a,(hl) ; read byte
out ($be),a; write to vram
add hl,de ; skip 8 bytes
djnz -
pop hl
inc hl ; next interleaving run
dec c
jr nz,--
; Add 32 bytes to vram_ptr
ld hl,(vram_ptr)
ld bc,32
add hl,bc
ld (vram_ptr),hl
pop bc
dec bc ; next tile
ld a,b
or c
jp nz,_DecompressTile
ret ; done