flamewing / mdcomp

Assorted compression formats for the Sega Mega Drive
Other
44 stars 4 forks source link

Space Harrier II graphics compression #27

Open DevsArchive opened 2 years ago

DevsArchive commented 2 years ago

Space Harrier 2 has an interesting, but simple graphics compression algorithm.

It has a 32 byte decompression buffer for holding decompressed tile data. For each tile, it'll use a list of bitfields that describe the places in the decompression buffer to copy a field's corresponding byte into. It is then finished off with a string of bytes that then fill up the rest of the unwritten to spots. The buffer is then copied to VRAM and it loops. It does this until it hits a termination flag.

; ---------------------------------------------------------------------------
; Space Harrier II graphics decompression
; VDP write command should be set before calling this
; ---------------------------------------------------------------------------
; PARAMETERS:
;   a0.l - Pointer to compressed art
; ---------------------------------------------------------------------------

SH2GfxDecomp:
        lea $FFF2C0.w,a3        ; Decompression buffer
        moveq   #0,d0           ; Buffer write flags

        moveq   #0,d2           ; Get number of bitfield copies for this tile
        move.b  (a0)+,d2
        beq.w   .CopyRest       ; If there are none, branch
        bmi.w   .End            ; If this is the end of the compressed data, branch
        subq.w  #1,d2           ; Subtract 1 for dbf

; ---------------------------------------------------------------------------

.GetCopyPattern:
        lea $FFF2C0.w,a2        ; Decompression buffer
        movea.l a2,a3

        move.b  (a0)+,d3        ; Get byte to copy
        move.b  (a0)+,d4        ; Get copy pattern
        lsl.w   #8,d4
        move.b  (a0)+,d4
        lsl.l   #8,d4
        move.b  (a0)+,d4
        lsl.l   #8,d4
        move.b  (a0)+,d4
        or.l     d4,d0          ; Mark spots in pattern as written to

        moveq   #32-1,d7        ; Start checking which places in buffer to copy byte into

.CopyByteLoop:
        lsl.l   #1,d4           ; Shift copy pattern and get MSB
        bcc.w   .AdvanceCopy        ; If the byte shouldn't be written to this spot, branch
        move.b  d3,(a2)         ; If it should, write it

.AdvanceCopy:
        addq.l  #1,a2           ; Go to next byte in buffer
        dbf d7,.CopyByteLoop    ; Loop until the whole copy pattern is scanned
        dbf d2,.GetCopyPattern  ; Loop until all copy patterns are scanned for this tile

; ---------------------------------------------------------------------------

        moveq   #$FFFFFFFF,d1       ; Is the whole buffer filled up?
        eor.l   d0,d1
        beq.w   .CopyToVRAM     ; If so, branch

.CopyRest:
        moveq   #32-1,d7        ; Start copying the rest of the tile data

.CopyRestLoop:
        lsl.l   #1,d0           ; Shift remaining pattern and get MSB
        bcs.w   .AdvanceRest        ; If the next byte shouldn't be written to this spot, branch
        move.b  (a0)+,(a3)      ; Copy byte and advance

.AdvanceRest:
        addq.l  #1,a3           ; Go to next byte in buffer
        dbf d7,.CopyRestLoop    ; Loop until the rest of the buffer is filled up

; ---------------------------------------------------------------------------

.CopyToVRAM:
        lea $FFF2C0.w,a6        ; Copy buffer to VRAM
        lea $C00000,a5
        move.l  (a6)+,(a5)
        move.l  (a6)+,(a5)
        move.l  (a6)+,(a5)
        move.l  (a6)+,(a5)
        move.l  (a6)+,(a5)
        move.l  (a6)+,(a5)
        move.l  (a6)+,(a5)
        move.l  (a6)+,(a5)

        bra.s   SH2GfxDecomp        ; Loop back to start for next tile

.End:
        rts