Sonic2TileLoader_Decompress:
  ; Set VDP address
  ld c,$bf
  out (c),e
  out (c),d

  push hl
    ; Skip header
    inc hl
    inc hl
    ; Read tile count
    ld a, (hl)
    ld (Sonic2TileLoader_TileCount), a
    inc hl
    ld a, (hl)
    ld (Sonic2TileLoader_TileCount+1), a
    inc hl
    ; Read bitstream pointer
    ld e, (hl)
    inc hl
    ld d, (hl)
    inc hl
    ; Data starts here
    ld (Sonic2TileLoader_DataPointer), hl
  pop hl
  add hl, de
  ld (Sonic2TileLoader_BitStreamPointer), hl

  ; Reset the consumed tile counter
  xor a
  ld (Sonic2TileLoader_BitstreamTileCounter), a

➿:
  ld a, (Sonic2TileLoader_BitstreamTileCounter)
  cp 4
  jr nz, +
  ; Read next byte from bitstream
  ld hl, (Sonic2TileLoader_BitStreamPointer)
  inc hl
  ld (Sonic2TileLoader_BitStreamPointer), hl
  xor a
  ld (Sonic2TileLoader_BitstreamTileCounter), a

+:; Get the current bitstream byte
  ld b, a
  ld hl, (Sonic2TileLoader_BitStreamPointer)
  ld a, (hl)
  ; Get the right two bits in the low two according to the value of Sonic2TileLoader_BitstreamTileCounter
-:dec b
  jp m, +
  rrca
  rrca
  jp -

+:ld hl,Sonic2TileLoader_BitstreamTileCounter
  inc (hl)
  and %11 ; Mask to two bits

  ; Type 0 = all zero
  jr z, _emitZeroBuffer

  dec a
  ; Type 1 = raw
  jr z,_raw

  push af
    ; Type 2 or 3 both need this

    ; Output pointer
    ld ix, Sonic2TileLoader_DecompressedData
    ; Get 32 bits of flags
    ld hl, (Sonic2TileLoader_DataPointer)
    ld e, (hl)
    inc hl
    ld d, (hl)
    inc hl
    ld c, (hl)
    inc hl
    ld b, (hl)
    inc hl
    ld a, 32 ; bit counter
-:  push af
      ; Rotate a bit out
      rr b
      rr c
      rr d
      rr e
      jr c, +
      ; 0 => emit a 0
      ld (ix+0), 0
      jr ++

+:    ; 1 => emit a byte
      ld a, (hl)
      ld (ix+0), a
      inc hl

++:   inc ix
    pop af
    ; Repeat 32 times
    dec a
    jr nz, -
    ld (Sonic2TileLoader_DataPointer), hl
  pop af
  dec a
  ; Only XOR for type 3
  call nz, _xor
  ; Fall through

  ld hl, Sonic2TileLoader_DecompressedData
  ld b, 32
-:ld a, (hl)
  out ($be), a
  inc hl
  djnz -
  ; fall through

_tileDone:
  ; Count down the tile count until done
  ld hl, (Sonic2TileLoader_TileCount)
  dec hl
  ld (Sonic2TileLoader_TileCount), hl
  ld a, l
  or h
  ret z
  jp

_raw:
  ; Emit 32 bytes
  ld hl, (Sonic2TileLoader_DataPointer)
  ld b, 32
-:ld a, (hl)
  out ($be), a
  inc hl
  djnz -
  ld (Sonic2TileLoader_DataPointer),hl
  jp _tileDone

_emitZeroBuffer:
  ; a must be 0 to get here
.repeat 32
  out ($be),a
.endr
  jp _tileDone

_xor:
  ld ix, Sonic2TileLoader_DecompressedData
  ld b, 7
-:; XOR bytes against each other across bitplanes on a few rows
  ; We end up using XORed bytes as values XORed later so this is not symmetric, it must be done in reverse order when compressing
  ld a, (ix+0)
  xor (ix+2)
  ld (ix+2), a
  ld a, (ix+1)
  xor (ix+3)
  ld (ix+3), a
  ld a, (ix+16)
  xor (ix+18)
  ld (ix+18), a
  ld a, (ix+17)
  xor (ix+19)
  ld (ix+19), a
  inc ix
  inc ix
  djnz -
  ret

See Compression for more discussion.




Return to top
0.309s