mirror of
https://github.com/pret/pokered.git
synced 2024-10-22 22:55:31 +00:00
home/pic.asm -> home/uncompress.asm; home/uncompress.asm -> home/pics.asm
One does the actual decompression, the other synthesizes the decompressed data.
This commit is contained in:
parent
f9dc42a740
commit
9b144cf647
4 changed files with 767 additions and 767 deletions
4
home.asm
4
home.asm
|
@ -74,7 +74,7 @@ LoadDestinationWarpPosition::
|
|||
|
||||
INCLUDE "home/pokemon.asm"
|
||||
INCLUDE "home/print_bcd.asm"
|
||||
INCLUDE "home/uncompress.asm"
|
||||
INCLUDE "home/pics.asm"
|
||||
INCLUDE "data/tilesets/collision_tile_ids.asm"
|
||||
INCLUDE "home/copy2.asm"
|
||||
INCLUDE "home/text.asm"
|
||||
|
@ -103,7 +103,7 @@ UpdateSprites::
|
|||
|
||||
INCLUDE "data/items/marts.asm"
|
||||
INCLUDE "home/overworld_text.asm"
|
||||
INCLUDE "home/pic.asm"
|
||||
INCLUDE "home/uncompress.asm"
|
||||
|
||||
ResetPlayerSpriteData::
|
||||
ld hl, wSpriteStateData1
|
||||
|
|
591
home/pic.asm
591
home/pic.asm
|
@ -1,591 +0,0 @@
|
|||
; bankswitches and runs _UncompressSpriteData
|
||||
; bank is given in a, sprite input stream is pointed to in wSpriteInputPtr
|
||||
UncompressSpriteData::
|
||||
ld b, a
|
||||
ld a, [hLoadedROMBank]
|
||||
push af
|
||||
ld a, b
|
||||
ld [hLoadedROMBank], a
|
||||
ld [MBC1RomBank], a
|
||||
ld a, SRAM_ENABLE
|
||||
ld [MBC1SRamEnable], a
|
||||
xor a
|
||||
ld [MBC1SRamBank], a
|
||||
call _UncompressSpriteData
|
||||
pop af
|
||||
ld [hLoadedROMBank], a
|
||||
ld [MBC1RomBank], a
|
||||
ret
|
||||
|
||||
; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
|
||||
_UncompressSpriteData::
|
||||
ld hl, sSpriteBuffer1
|
||||
ld c, (2*SPRITEBUFFERSIZE) % $100
|
||||
ld b, (2*SPRITEBUFFERSIZE) / $100
|
||||
xor a
|
||||
call FillMemory ; clear sprite buffer 1 and 2
|
||||
ld a, $1
|
||||
ld [wSpriteInputBitCounter], a
|
||||
ld a, $3
|
||||
ld [wSpriteOutputBitOffset], a
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld [wSpriteCurPosY], a
|
||||
ld [wSpriteLoadFlags], a
|
||||
call ReadNextInputByte ; first byte of input determines sprite width (high nybble) and height (low nybble) in tiles (8x8 pixels)
|
||||
ld b, a
|
||||
and $f
|
||||
add a
|
||||
add a
|
||||
add a
|
||||
ld [wSpriteHeight], a
|
||||
ld a, b
|
||||
swap a
|
||||
and $f
|
||||
add a
|
||||
add a
|
||||
add a
|
||||
ld [wSpriteWidth], a
|
||||
call ReadNextInputBit
|
||||
ld [wSpriteLoadFlags], a ; initialite bit1 to 0 and bit0 to the first input bit
|
||||
; this will load two chunks of data to sSpriteBuffer1 and sSpriteBuffer2
|
||||
; bit 0 decides in which one the first chunk is placed
|
||||
; fall through
|
||||
|
||||
; uncompresses a chunk from the sprite input data stream (pointed to at wd0da) into sSpriteBuffer1 or sSpriteBuffer2
|
||||
; each chunk is a 1bpp sprite. A 2bpp sprite consist of two chunks which are merged afterwards
|
||||
; note that this is an endless loop which is terminated during a call to MoveToNextBufferPosition by manipulating the stack
|
||||
UncompressSpriteDataLoop::
|
||||
ld hl, sSpriteBuffer1
|
||||
ld a, [wSpriteLoadFlags]
|
||||
bit 0, a
|
||||
jr z, .useSpriteBuffer1 ; check which buffer to use
|
||||
ld hl, sSpriteBuffer2
|
||||
.useSpriteBuffer1
|
||||
call StoreSpriteOutputPointer
|
||||
ld a, [wSpriteLoadFlags]
|
||||
bit 1, a
|
||||
jr z, .startDecompression ; check if last iteration
|
||||
call ReadNextInputBit ; if last chunk, read 1-2 bit unpacking mode
|
||||
and a
|
||||
jr z, .unpackingMode0 ; 0 -> mode 0
|
||||
call ReadNextInputBit ; 1 0 -> mode 1
|
||||
inc a ; 1 1 -> mode 2
|
||||
.unpackingMode0
|
||||
ld [wSpriteUnpackMode], a
|
||||
.startDecompression
|
||||
call ReadNextInputBit
|
||||
and a
|
||||
jr z, .readRLEncodedZeros ; if first bit is 0, the input starts with zeroes, otherwise with (non-zero) input
|
||||
.readNextInput
|
||||
call ReadNextInputBit
|
||||
ld c, a
|
||||
call ReadNextInputBit
|
||||
sla c
|
||||
or c ; read next two bits into c
|
||||
and a
|
||||
jr z, .readRLEncodedZeros ; 00 -> RLEncoded zeroes following
|
||||
call WriteSpriteBitsToBuffer ; otherwise write input to output and repeat
|
||||
call MoveToNextBufferPosition
|
||||
jr .readNextInput
|
||||
.readRLEncodedZeros
|
||||
ld c, $0 ; number of zeroes it length encoded, the number
|
||||
.countConsecutiveOnesLoop ; of consecutive ones determines the number of bits the number has
|
||||
call ReadNextInputBit
|
||||
and a
|
||||
jr z, .countConsecutiveOnesFinished
|
||||
inc c
|
||||
jr .countConsecutiveOnesLoop
|
||||
.countConsecutiveOnesFinished
|
||||
ld a, c
|
||||
add a
|
||||
ld hl, LengthEncodingOffsetList
|
||||
add l
|
||||
ld l, a
|
||||
jr nc, .noCarry
|
||||
inc h
|
||||
.noCarry
|
||||
ld a, [hli] ; read offset that is added to the number later on
|
||||
ld e, a ; adding an offset of 2^length - 1 makes every integer uniquely
|
||||
ld d, [hl] ; representable in the length encoding and saves bits
|
||||
push de
|
||||
inc c
|
||||
ld e, $0
|
||||
ld d, e
|
||||
.readNumberOfZerosLoop ; reads the next c+1 bits of input
|
||||
call ReadNextInputBit
|
||||
or e
|
||||
ld e, a
|
||||
dec c
|
||||
jr z, .readNumberOfZerosDone
|
||||
sla e
|
||||
rl d
|
||||
jr .readNumberOfZerosLoop
|
||||
.readNumberOfZerosDone
|
||||
pop hl ; add the offset
|
||||
add hl, de
|
||||
ld e, l
|
||||
ld d, h
|
||||
.writeZerosLoop
|
||||
ld b, e
|
||||
xor a ; write 00 to buffer
|
||||
call WriteSpriteBitsToBuffer
|
||||
ld e, b
|
||||
call MoveToNextBufferPosition
|
||||
dec de
|
||||
ld a, d
|
||||
and a
|
||||
jr nz, .continueLoop
|
||||
ld a, e
|
||||
and a
|
||||
.continueLoop
|
||||
jr nz, .writeZerosLoop
|
||||
jr .readNextInput
|
||||
|
||||
; moves output pointer to next position
|
||||
; also cancels the calling function if the all output is done (by removing the return pointer from stack)
|
||||
; and calls postprocessing functions according to the unpack mode
|
||||
MoveToNextBufferPosition::
|
||||
ld a, [wSpriteHeight]
|
||||
ld b, a
|
||||
ld a, [wSpriteCurPosY]
|
||||
inc a
|
||||
cp b
|
||||
jr z, .curColumnDone
|
||||
ld [wSpriteCurPosY], a
|
||||
ld a, [wSpriteOutputPtr]
|
||||
inc a
|
||||
ld [wSpriteOutputPtr], a
|
||||
ret nz
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
inc a
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ret
|
||||
.curColumnDone
|
||||
xor a
|
||||
ld [wSpriteCurPosY], a
|
||||
ld a, [wSpriteOutputBitOffset]
|
||||
and a
|
||||
jr z, .bitOffsetsDone
|
||||
dec a
|
||||
ld [wSpriteOutputBitOffset], a
|
||||
ld hl, wSpriteOutputPtrCached
|
||||
ld a, [hli]
|
||||
ld [wSpriteOutputPtr], a
|
||||
ld a, [hl]
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ret
|
||||
.bitOffsetsDone
|
||||
ld a, $3
|
||||
ld [wSpriteOutputBitOffset], a
|
||||
ld a, [wSpriteCurPosX]
|
||||
add $8
|
||||
ld [wSpriteCurPosX], a
|
||||
ld b, a
|
||||
ld a, [wSpriteWidth]
|
||||
cp b
|
||||
jr z, .allColumnsDone
|
||||
ld a, [wSpriteOutputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
inc hl
|
||||
jp StoreSpriteOutputPointer
|
||||
.allColumnsDone
|
||||
pop hl
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld a, [wSpriteLoadFlags]
|
||||
bit 1, a
|
||||
jr nz, .done ; test if there is one more sprite to go
|
||||
xor $1
|
||||
set 1, a
|
||||
ld [wSpriteLoadFlags], a
|
||||
jp UncompressSpriteDataLoop
|
||||
.done
|
||||
jp UnpackSprite
|
||||
|
||||
; writes 2 bits (from a) to the output buffer (pointed to from wSpriteOutputPtr)
|
||||
WriteSpriteBitsToBuffer::
|
||||
ld e, a
|
||||
ld a, [wSpriteOutputBitOffset]
|
||||
and a
|
||||
jr z, .offset0
|
||||
cp $2
|
||||
jr c, .offset1
|
||||
jr z, .offset2
|
||||
rrc e ; offset 3
|
||||
rrc e
|
||||
jr .offset0
|
||||
.offset1
|
||||
sla e
|
||||
sla e
|
||||
jr .offset0
|
||||
.offset2
|
||||
swap e
|
||||
.offset0
|
||||
ld a, [wSpriteOutputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
ld a, [hl]
|
||||
or e
|
||||
ld [hl], a
|
||||
ret
|
||||
|
||||
; reads next bit from input stream and returns it in a
|
||||
ReadNextInputBit::
|
||||
ld a, [wSpriteInputBitCounter]
|
||||
dec a
|
||||
jr nz, .curByteHasMoreBitsToRead
|
||||
call ReadNextInputByte
|
||||
ld [wSpriteInputCurByte], a
|
||||
ld a, $8
|
||||
.curByteHasMoreBitsToRead
|
||||
ld [wSpriteInputBitCounter], a
|
||||
ld a, [wSpriteInputCurByte]
|
||||
rlca
|
||||
ld [wSpriteInputCurByte], a
|
||||
and $1
|
||||
ret
|
||||
|
||||
; reads next byte from input stream and returns it in a
|
||||
ReadNextInputByte::
|
||||
ld a, [wSpriteInputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteInputPtr+1]
|
||||
ld h, a
|
||||
ld a, [hli]
|
||||
ld b, a
|
||||
ld a, l
|
||||
ld [wSpriteInputPtr], a
|
||||
ld a, h
|
||||
ld [wSpriteInputPtr+1], a
|
||||
ld a, b
|
||||
ret
|
||||
|
||||
; the nth item is 2^n - 1
|
||||
LengthEncodingOffsetList::
|
||||
dw %0000000000000001
|
||||
dw %0000000000000011
|
||||
dw %0000000000000111
|
||||
dw %0000000000001111
|
||||
dw %0000000000011111
|
||||
dw %0000000000111111
|
||||
dw %0000000001111111
|
||||
dw %0000000011111111
|
||||
dw %0000000111111111
|
||||
dw %0000001111111111
|
||||
dw %0000011111111111
|
||||
dw %0000111111111111
|
||||
dw %0001111111111111
|
||||
dw %0011111111111111
|
||||
dw %0111111111111111
|
||||
dw %1111111111111111
|
||||
|
||||
; unpacks the sprite data depending on the unpack mode
|
||||
UnpackSprite::
|
||||
ld a, [wSpriteUnpackMode]
|
||||
cp $2
|
||||
jp z, UnpackSpriteMode2
|
||||
and a
|
||||
jp nz, XorSpriteChunks
|
||||
ld hl, sSpriteBuffer1
|
||||
call SpriteDifferentialDecode
|
||||
ld hl, sSpriteBuffer2
|
||||
; fall through
|
||||
|
||||
; decodes differential encoded sprite data
|
||||
; input bit value 0 preserves the current bit value and input bit value 1 toggles it (starting from initial value 0).
|
||||
SpriteDifferentialDecode::
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld [wSpriteCurPosY], a
|
||||
call StoreSpriteOutputPointer
|
||||
ld a, [wSpriteFlipped]
|
||||
and a
|
||||
jr z, .notFlipped
|
||||
ld hl, DecodeNybble0TableFlipped
|
||||
ld de, DecodeNybble1TableFlipped
|
||||
jr .storeDecodeTablesPointers
|
||||
.notFlipped
|
||||
ld hl, DecodeNybble0Table
|
||||
ld de, DecodeNybble1Table
|
||||
.storeDecodeTablesPointers
|
||||
ld a, l
|
||||
ld [wSpriteDecodeTable0Ptr], a
|
||||
ld a, h
|
||||
ld [wSpriteDecodeTable0Ptr+1], a
|
||||
ld a, e
|
||||
ld [wSpriteDecodeTable1Ptr], a
|
||||
ld a, d
|
||||
ld [wSpriteDecodeTable1Ptr+1], a
|
||||
ld e, $0 ; last decoded nybble, initialized to 0
|
||||
.decodeNextByteLoop
|
||||
ld a, [wSpriteOutputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
ld a, [hl]
|
||||
ld b, a
|
||||
swap a
|
||||
and $f
|
||||
call DifferentialDecodeNybble ; decode high nybble
|
||||
swap a
|
||||
ld d, a
|
||||
ld a, b
|
||||
and $f
|
||||
call DifferentialDecodeNybble ; decode low nybble
|
||||
or d
|
||||
ld b, a
|
||||
ld a, [wSpriteOutputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
ld a, b
|
||||
ld [hl], a ; write back decoded data
|
||||
ld a, [wSpriteHeight]
|
||||
add l ; move on to next column
|
||||
jr nc, .noCarry
|
||||
inc h
|
||||
.noCarry
|
||||
ld [wSpriteOutputPtr], a
|
||||
ld a, h
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ld a, [wSpriteCurPosX]
|
||||
add $8
|
||||
ld [wSpriteCurPosX], a
|
||||
ld b, a
|
||||
ld a, [wSpriteWidth]
|
||||
cp b
|
||||
jr nz, .decodeNextByteLoop ; test if current row is done
|
||||
xor a
|
||||
ld e, a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld a, [wSpriteCurPosY] ; move on to next row
|
||||
inc a
|
||||
ld [wSpriteCurPosY], a
|
||||
ld b, a
|
||||
ld a, [wSpriteHeight]
|
||||
cp b
|
||||
jr z, .done ; test if all rows finished
|
||||
ld a, [wSpriteOutputPtrCached]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtrCached+1]
|
||||
ld h, a
|
||||
inc hl
|
||||
call StoreSpriteOutputPointer
|
||||
jr .decodeNextByteLoop
|
||||
.done
|
||||
xor a
|
||||
ld [wSpriteCurPosY], a
|
||||
ret
|
||||
|
||||
; decodes the nybble stored in a. Last decoded data is assumed to be in e (needed to determine if initial value is 0 or 1)
|
||||
DifferentialDecodeNybble::
|
||||
srl a ; c=a%2, a/=2
|
||||
ld c, $0
|
||||
jr nc, .evenNumber
|
||||
ld c, $1
|
||||
.evenNumber
|
||||
ld l, a
|
||||
ld a, [wSpriteFlipped]
|
||||
and a
|
||||
jr z, .notFlipped ; determine if initial value is 0 or one
|
||||
bit 3, e ; if flipped, consider MSB of last data
|
||||
jr .selectLookupTable
|
||||
.notFlipped
|
||||
bit 0, e ; else consider LSB
|
||||
.selectLookupTable
|
||||
ld e, l
|
||||
jr nz, .initialValue1 ; load the appropriate table
|
||||
ld a, [wSpriteDecodeTable0Ptr]
|
||||
ld l, a
|
||||
ld a, [wSpriteDecodeTable0Ptr+1]
|
||||
jr .tableLookup
|
||||
.initialValue1
|
||||
ld a, [wSpriteDecodeTable1Ptr]
|
||||
ld l, a
|
||||
ld a, [wSpriteDecodeTable1Ptr+1]
|
||||
.tableLookup
|
||||
ld h, a
|
||||
ld a, e
|
||||
add l
|
||||
ld l, a
|
||||
jr nc, .noCarry
|
||||
inc h
|
||||
.noCarry
|
||||
ld a, [hl]
|
||||
bit 0, c
|
||||
jr nz, .selectLowNybble
|
||||
swap a ; select high nybble
|
||||
.selectLowNybble
|
||||
and $f
|
||||
ld e, a ; update last decoded data
|
||||
ret
|
||||
|
||||
DecodeNybble0Table::
|
||||
dn $0, $1
|
||||
dn $3, $2
|
||||
dn $7, $6
|
||||
dn $4, $5
|
||||
dn $f, $e
|
||||
dn $c, $d
|
||||
dn $8, $9
|
||||
dn $b, $a
|
||||
DecodeNybble1Table::
|
||||
dn $f, $e
|
||||
dn $c, $d
|
||||
dn $8, $9
|
||||
dn $b, $a
|
||||
dn $0, $1
|
||||
dn $3, $2
|
||||
dn $7, $6
|
||||
dn $4, $5
|
||||
DecodeNybble0TableFlipped::
|
||||
dn $0, $8
|
||||
dn $c, $4
|
||||
dn $e, $6
|
||||
dn $2, $a
|
||||
dn $f, $7
|
||||
dn $3, $b
|
||||
dn $1, $9
|
||||
dn $d, $5
|
||||
DecodeNybble1TableFlipped::
|
||||
dn $f, $7
|
||||
dn $3, $b
|
||||
dn $1, $9
|
||||
dn $d, $5
|
||||
dn $0, $8
|
||||
dn $c, $4
|
||||
dn $e, $6
|
||||
dn $2, $a
|
||||
|
||||
; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differeintial decoded beforehand.
|
||||
XorSpriteChunks::
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld [wSpriteCurPosY], a
|
||||
call ResetSpriteBufferPointers
|
||||
ld a, [wSpriteOutputPtr] ; points to buffer 1 or 2, depending on flags
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
call SpriteDifferentialDecode ; decode buffer 1 or 2, depending on flags
|
||||
call ResetSpriteBufferPointers
|
||||
ld a, [wSpriteOutputPtr] ; source buffer, points to buffer 1 or 2, depending on flags
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
ld a, [wSpriteOutputPtrCached] ; destination buffer, points to buffer 2 or 1, depending on flags
|
||||
ld e, a
|
||||
ld a, [wSpriteOutputPtrCached+1]
|
||||
ld d, a
|
||||
.xorChunksLoop
|
||||
ld a, [wSpriteFlipped]
|
||||
and a
|
||||
jr z, .notFlipped
|
||||
push de
|
||||
ld a, [de]
|
||||
ld b, a
|
||||
swap a
|
||||
and $f
|
||||
call ReverseNybble ; if flipped reverse the nybbles in the destination buffer
|
||||
swap a
|
||||
ld c, a
|
||||
ld a, b
|
||||
and $f
|
||||
call ReverseNybble
|
||||
or c
|
||||
pop de
|
||||
ld [de], a
|
||||
.notFlipped
|
||||
ld a, [hli]
|
||||
ld b, a
|
||||
ld a, [de]
|
||||
xor b
|
||||
ld [de], a
|
||||
inc de
|
||||
ld a, [wSpriteCurPosY]
|
||||
inc a
|
||||
ld [wSpriteCurPosY], a ; go to next row
|
||||
ld b, a
|
||||
ld a, [wSpriteHeight]
|
||||
cp b
|
||||
jr nz, .xorChunksLoop ; test if column finished
|
||||
xor a
|
||||
ld [wSpriteCurPosY], a
|
||||
ld a, [wSpriteCurPosX]
|
||||
add $8
|
||||
ld [wSpriteCurPosX], a ; go to next column
|
||||
ld b, a
|
||||
ld a, [wSpriteWidth]
|
||||
cp b
|
||||
jr nz, .xorChunksLoop ; test if all columns finished
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ret
|
||||
|
||||
; reverses the bits in the nybble given in register a
|
||||
ReverseNybble::
|
||||
ld de, NybbleReverseTable
|
||||
add e
|
||||
ld e, a
|
||||
jr nc, .noCarry
|
||||
inc d
|
||||
.noCarry
|
||||
ld a, [de]
|
||||
ret
|
||||
|
||||
; resets sprite buffer pointers to buffer 1 and 2, depending on wSpriteLoadFlags
|
||||
ResetSpriteBufferPointers::
|
||||
ld a, [wSpriteLoadFlags]
|
||||
bit 0, a
|
||||
jr nz, .buffer2Selected
|
||||
ld de, sSpriteBuffer1
|
||||
ld hl, sSpriteBuffer2
|
||||
jr .storeBufferPointers
|
||||
.buffer2Selected
|
||||
ld de, sSpriteBuffer2
|
||||
ld hl, sSpriteBuffer1
|
||||
.storeBufferPointers
|
||||
ld a, l
|
||||
ld [wSpriteOutputPtr], a
|
||||
ld a, h
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ld a, e
|
||||
ld [wSpriteOutputPtrCached], a
|
||||
ld a, d
|
||||
ld [wSpriteOutputPtrCached+1], a
|
||||
ret
|
||||
|
||||
; maps each nybble to its reverse
|
||||
NybbleReverseTable::
|
||||
db $0, $8, $4, $c, $2, $a, $6 ,$e, $1, $9, $5, $d, $3, $b, $7 ,$f
|
||||
|
||||
; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differeintial decoded beforehand.
|
||||
UnpackSpriteMode2::
|
||||
call ResetSpriteBufferPointers
|
||||
ld a, [wSpriteFlipped]
|
||||
push af
|
||||
xor a
|
||||
ld [wSpriteFlipped], a ; temporarily clear flipped flag for decoding the destination chunk
|
||||
ld a, [wSpriteOutputPtrCached]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtrCached+1]
|
||||
ld h, a
|
||||
call SpriteDifferentialDecode
|
||||
call ResetSpriteBufferPointers
|
||||
pop af
|
||||
ld [wSpriteFlipped], a
|
||||
jp XorSpriteChunks
|
||||
|
||||
; stores hl into the output pointers
|
||||
StoreSpriteOutputPointer::
|
||||
ld a, l
|
||||
ld [wSpriteOutputPtr], a
|
||||
ld [wSpriteOutputPtrCached], a
|
||||
ld a, h
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ld [wSpriteOutputPtrCached+1], a
|
||||
ret
|
196
home/pics.asm
Normal file
196
home/pics.asm
Normal file
|
@ -0,0 +1,196 @@
|
|||
; uncompresses the front or back sprite of the specified mon
|
||||
; assumes the corresponding mon header is already loaded
|
||||
; hl contains offset to sprite pointer ($b for front or $d for back)
|
||||
UncompressMonSprite::
|
||||
ld bc, wMonHeader
|
||||
add hl, bc
|
||||
ld a, [hli]
|
||||
ld [wSpriteInputPtr], a ; fetch sprite input pointer
|
||||
ld a, [hl]
|
||||
ld [wSpriteInputPtr+1], a
|
||||
; define (by index number) the bank that a pokemon's image is in
|
||||
; index = Mew, bank 1
|
||||
; index = Kabutops fossil, bank $B
|
||||
; index < $1F, bank 9
|
||||
; $1F ≤ index < $4A, bank $A
|
||||
; $4A ≤ index < $74, bank $B
|
||||
; $74 ≤ index < $99, bank $C
|
||||
; $99 ≤ index, bank $D
|
||||
ld a, [wcf91] ; XXX name for this ram location
|
||||
ld b, a
|
||||
cp MEW
|
||||
ld a, BANK(MewPicFront)
|
||||
jr z, .GotBank
|
||||
ld a, b
|
||||
cp FOSSIL_KABUTOPS
|
||||
ld a, BANK(FossilKabutopsPic)
|
||||
jr z, .GotBank
|
||||
ld a, b
|
||||
cp TANGELA + 1
|
||||
ld a, BANK(TangelaPicFront)
|
||||
jr c, .GotBank
|
||||
ld a, b
|
||||
cp MOLTRES + 1
|
||||
ld a, BANK(MoltresPicFront)
|
||||
jr c, .GotBank
|
||||
ld a, b
|
||||
cp BEEDRILL + 2
|
||||
ld a, BANK(BeedrillPicFront)
|
||||
jr c, .GotBank
|
||||
ld a, b
|
||||
cp STARMIE + 1
|
||||
ld a, BANK(StarmiePicFront)
|
||||
jr c, .GotBank
|
||||
ld a, BANK(VictreebelPicFront)
|
||||
.GotBank
|
||||
jp UncompressSpriteData
|
||||
|
||||
; de: destination location
|
||||
LoadMonFrontSprite::
|
||||
push de
|
||||
ld hl, wMonHFrontSprite - wMonHeader
|
||||
call UncompressMonSprite
|
||||
ld hl, wMonHSpriteDim
|
||||
ld a, [hli]
|
||||
ld c, a
|
||||
pop de
|
||||
; fall through
|
||||
|
||||
; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram
|
||||
; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers
|
||||
; de: destination location
|
||||
; a,c: sprite dimensions (in tiles of 8x8 each)
|
||||
LoadUncompressedSpriteData::
|
||||
push de
|
||||
and $f
|
||||
ld [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width
|
||||
ld b, a
|
||||
ld a, $7
|
||||
sub b ; 7-w
|
||||
inc a ; 8-w
|
||||
srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up)
|
||||
ld b, a
|
||||
add a
|
||||
add a
|
||||
add a
|
||||
sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles)
|
||||
ld [hSpriteOffset], a
|
||||
ld a, c
|
||||
swap a
|
||||
and $f
|
||||
ld b, a
|
||||
add a
|
||||
add a
|
||||
add a ; 8*tiles is height in bytes
|
||||
ld [hSpriteHeight], a
|
||||
ld a, $7
|
||||
sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
|
||||
ld b, a
|
||||
ld a, [hSpriteOffset]
|
||||
add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles)
|
||||
add a
|
||||
add a
|
||||
add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes)
|
||||
ld [hSpriteOffset], a
|
||||
xor a
|
||||
ld [$4000], a
|
||||
ld hl, sSpriteBuffer0
|
||||
call ZeroSpriteBuffer ; zero buffer 0
|
||||
ld de, sSpriteBuffer1
|
||||
ld hl, sSpriteBuffer0
|
||||
call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
|
||||
ld hl, sSpriteBuffer1
|
||||
call ZeroSpriteBuffer ; zero buffer 1
|
||||
ld de, sSpriteBuffer2
|
||||
ld hl, sSpriteBuffer1
|
||||
call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
|
||||
pop de
|
||||
jp InterlaceMergeSpriteBuffers
|
||||
|
||||
; copies and aligns the sprite data properly inside the sprite buffer
|
||||
; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area
|
||||
AlignSpriteDataCentered::
|
||||
ld a, [hSpriteOffset]
|
||||
ld b, $0
|
||||
ld c, a
|
||||
add hl, bc
|
||||
ld a, [hSpriteWidth]
|
||||
.columnLoop
|
||||
push af
|
||||
push hl
|
||||
ld a, [hSpriteHeight]
|
||||
ld c, a
|
||||
.columnInnerLoop
|
||||
ld a, [de]
|
||||
inc de
|
||||
ld [hli], a
|
||||
dec c
|
||||
jr nz, .columnInnerLoop
|
||||
pop hl
|
||||
ld bc, 7*8 ; 7 tiles
|
||||
add hl, bc ; advance one full column
|
||||
pop af
|
||||
dec a
|
||||
jr nz, .columnLoop
|
||||
ret
|
||||
|
||||
; fills the sprite buffer (pointed to in hl) with zeros
|
||||
ZeroSpriteBuffer::
|
||||
ld bc, SPRITEBUFFERSIZE
|
||||
.nextByteLoop
|
||||
xor a
|
||||
ld [hli], a
|
||||
dec bc
|
||||
ld a, b
|
||||
or c
|
||||
jr nz, .nextByteLoop
|
||||
ret
|
||||
|
||||
; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2
|
||||
; in the resulting sprite, the rows of the two source sprites are interlaced
|
||||
; de: output address
|
||||
InterlaceMergeSpriteBuffers::
|
||||
xor a
|
||||
ld [$4000], a
|
||||
push de
|
||||
ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
|
||||
ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
|
||||
ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
|
||||
ld a, SPRITEBUFFERSIZE/2 ; $c4
|
||||
ld [hSpriteInterlaceCounter], a
|
||||
.interlaceLoop
|
||||
ld a, [de]
|
||||
dec de
|
||||
ld [hld], a ; write byte of source 2
|
||||
ld a, [bc]
|
||||
dec bc
|
||||
ld [hld], a ; write byte of source 1
|
||||
ld a, [de]
|
||||
dec de
|
||||
ld [hld], a ; write byte of source 2
|
||||
ld a, [bc]
|
||||
dec bc
|
||||
ld [hld], a ; write byte of source 1
|
||||
ld a, [hSpriteInterlaceCounter]
|
||||
dec a
|
||||
ld [hSpriteInterlaceCounter], a
|
||||
jr nz, .interlaceLoop
|
||||
ld a, [wSpriteFlipped]
|
||||
and a
|
||||
jr z, .notFlipped
|
||||
ld bc, 2*SPRITEBUFFERSIZE
|
||||
ld hl, sSpriteBuffer1
|
||||
.swapLoop
|
||||
swap [hl] ; if flipped swap nybbles in all bytes
|
||||
inc hl
|
||||
dec bc
|
||||
ld a, b
|
||||
or c
|
||||
jr nz, .swapLoop
|
||||
.notFlipped
|
||||
pop hl
|
||||
ld de, sSpriteBuffer1
|
||||
ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
|
||||
ld a, [hLoadedROMBank]
|
||||
ld b, a
|
||||
jp CopyVideoData
|
|
@ -1,196 +1,591 @@
|
|||
; uncompresses the front or back sprite of the specified mon
|
||||
; assumes the corresponding mon header is already loaded
|
||||
; hl contains offset to sprite pointer ($b for front or $d for back)
|
||||
UncompressMonSprite::
|
||||
ld bc, wMonHeader
|
||||
add hl, bc
|
||||
ld a, [hli]
|
||||
ld [wSpriteInputPtr], a ; fetch sprite input pointer
|
||||
ld a, [hl]
|
||||
ld [wSpriteInputPtr+1], a
|
||||
; define (by index number) the bank that a pokemon's image is in
|
||||
; index = Mew, bank 1
|
||||
; index = Kabutops fossil, bank $B
|
||||
; index < $1F, bank 9
|
||||
; $1F ≤ index < $4A, bank $A
|
||||
; $4A ≤ index < $74, bank $B
|
||||
; $74 ≤ index < $99, bank $C
|
||||
; $99 ≤ index, bank $D
|
||||
ld a, [wcf91] ; XXX name for this ram location
|
||||
; bankswitches and runs _UncompressSpriteData
|
||||
; bank is given in a, sprite input stream is pointed to in wSpriteInputPtr
|
||||
UncompressSpriteData::
|
||||
ld b, a
|
||||
cp MEW
|
||||
ld a, BANK(MewPicFront)
|
||||
jr z, .GotBank
|
||||
ld a, [hLoadedROMBank]
|
||||
push af
|
||||
ld a, b
|
||||
cp FOSSIL_KABUTOPS
|
||||
ld a, BANK(FossilKabutopsPic)
|
||||
jr z, .GotBank
|
||||
ld a, b
|
||||
cp TANGELA + 1
|
||||
ld a, BANK(TangelaPicFront)
|
||||
jr c, .GotBank
|
||||
ld a, b
|
||||
cp MOLTRES + 1
|
||||
ld a, BANK(MoltresPicFront)
|
||||
jr c, .GotBank
|
||||
ld a, b
|
||||
cp BEEDRILL + 2
|
||||
ld a, BANK(BeedrillPicFront)
|
||||
jr c, .GotBank
|
||||
ld a, b
|
||||
cp STARMIE + 1
|
||||
ld a, BANK(StarmiePicFront)
|
||||
jr c, .GotBank
|
||||
ld a, BANK(VictreebelPicFront)
|
||||
.GotBank
|
||||
jp UncompressSpriteData
|
||||
ld [hLoadedROMBank], a
|
||||
ld [MBC1RomBank], a
|
||||
ld a, SRAM_ENABLE
|
||||
ld [MBC1SRamEnable], a
|
||||
xor a
|
||||
ld [MBC1SRamBank], a
|
||||
call _UncompressSpriteData
|
||||
pop af
|
||||
ld [hLoadedROMBank], a
|
||||
ld [MBC1RomBank], a
|
||||
ret
|
||||
|
||||
; de: destination location
|
||||
LoadMonFrontSprite::
|
||||
push de
|
||||
ld hl, wMonHFrontSprite - wMonHeader
|
||||
call UncompressMonSprite
|
||||
ld hl, wMonHSpriteDim
|
||||
ld a, [hli]
|
||||
ld c, a
|
||||
pop de
|
||||
; fall through
|
||||
|
||||
; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram
|
||||
; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers
|
||||
; de: destination location
|
||||
; a,c: sprite dimensions (in tiles of 8x8 each)
|
||||
LoadUncompressedSpriteData::
|
||||
push de
|
||||
; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
|
||||
_UncompressSpriteData::
|
||||
ld hl, sSpriteBuffer1
|
||||
ld c, (2*SPRITEBUFFERSIZE) % $100
|
||||
ld b, (2*SPRITEBUFFERSIZE) / $100
|
||||
xor a
|
||||
call FillMemory ; clear sprite buffer 1 and 2
|
||||
ld a, $1
|
||||
ld [wSpriteInputBitCounter], a
|
||||
ld a, $3
|
||||
ld [wSpriteOutputBitOffset], a
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld [wSpriteCurPosY], a
|
||||
ld [wSpriteLoadFlags], a
|
||||
call ReadNextInputByte ; first byte of input determines sprite width (high nybble) and height (low nybble) in tiles (8x8 pixels)
|
||||
ld b, a
|
||||
and $f
|
||||
ld [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width
|
||||
ld b, a
|
||||
ld a, $7
|
||||
sub b ; 7-w
|
||||
inc a ; 8-w
|
||||
srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up)
|
||||
ld b, a
|
||||
add a
|
||||
add a
|
||||
add a
|
||||
sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles)
|
||||
ld [hSpriteOffset], a
|
||||
ld a, c
|
||||
ld [wSpriteHeight], a
|
||||
ld a, b
|
||||
swap a
|
||||
and $f
|
||||
ld b, a
|
||||
add a
|
||||
add a
|
||||
add a ; 8*tiles is height in bytes
|
||||
ld [hSpriteHeight], a
|
||||
ld a, $7
|
||||
sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
|
||||
ld b, a
|
||||
ld a, [hSpriteOffset]
|
||||
add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles)
|
||||
add a
|
||||
add a
|
||||
add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes)
|
||||
ld [hSpriteOffset], a
|
||||
xor a
|
||||
ld [$4000], a
|
||||
ld hl, sSpriteBuffer0
|
||||
call ZeroSpriteBuffer ; zero buffer 0
|
||||
ld de, sSpriteBuffer1
|
||||
ld hl, sSpriteBuffer0
|
||||
call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
|
||||
ld [wSpriteWidth], a
|
||||
call ReadNextInputBit
|
||||
ld [wSpriteLoadFlags], a ; initialite bit1 to 0 and bit0 to the first input bit
|
||||
; this will load two chunks of data to sSpriteBuffer1 and sSpriteBuffer2
|
||||
; bit 0 decides in which one the first chunk is placed
|
||||
; fall through
|
||||
|
||||
; uncompresses a chunk from the sprite input data stream (pointed to at wd0da) into sSpriteBuffer1 or sSpriteBuffer2
|
||||
; each chunk is a 1bpp sprite. A 2bpp sprite consist of two chunks which are merged afterwards
|
||||
; note that this is an endless loop which is terminated during a call to MoveToNextBufferPosition by manipulating the stack
|
||||
UncompressSpriteDataLoop::
|
||||
ld hl, sSpriteBuffer1
|
||||
call ZeroSpriteBuffer ; zero buffer 1
|
||||
ld de, sSpriteBuffer2
|
||||
ld hl, sSpriteBuffer1
|
||||
call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
|
||||
pop de
|
||||
jp InterlaceMergeSpriteBuffers
|
||||
|
||||
; copies and aligns the sprite data properly inside the sprite buffer
|
||||
; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area
|
||||
AlignSpriteDataCentered::
|
||||
ld a, [hSpriteOffset]
|
||||
ld b, $0
|
||||
ld a, [wSpriteLoadFlags]
|
||||
bit 0, a
|
||||
jr z, .useSpriteBuffer1 ; check which buffer to use
|
||||
ld hl, sSpriteBuffer2
|
||||
.useSpriteBuffer1
|
||||
call StoreSpriteOutputPointer
|
||||
ld a, [wSpriteLoadFlags]
|
||||
bit 1, a
|
||||
jr z, .startDecompression ; check if last iteration
|
||||
call ReadNextInputBit ; if last chunk, read 1-2 bit unpacking mode
|
||||
and a
|
||||
jr z, .unpackingMode0 ; 0 -> mode 0
|
||||
call ReadNextInputBit ; 1 0 -> mode 1
|
||||
inc a ; 1 1 -> mode 2
|
||||
.unpackingMode0
|
||||
ld [wSpriteUnpackMode], a
|
||||
.startDecompression
|
||||
call ReadNextInputBit
|
||||
and a
|
||||
jr z, .readRLEncodedZeros ; if first bit is 0, the input starts with zeroes, otherwise with (non-zero) input
|
||||
.readNextInput
|
||||
call ReadNextInputBit
|
||||
ld c, a
|
||||
add hl, bc
|
||||
ld a, [hSpriteWidth]
|
||||
.columnLoop
|
||||
push af
|
||||
push hl
|
||||
ld a, [hSpriteHeight]
|
||||
ld c, a
|
||||
.columnInnerLoop
|
||||
ld a, [de]
|
||||
inc de
|
||||
ld [hli], a
|
||||
dec c
|
||||
jr nz, .columnInnerLoop
|
||||
pop hl
|
||||
ld bc, 7*8 ; 7 tiles
|
||||
add hl, bc ; advance one full column
|
||||
pop af
|
||||
dec a
|
||||
jr nz, .columnLoop
|
||||
ret
|
||||
|
||||
; fills the sprite buffer (pointed to in hl) with zeros
|
||||
ZeroSpriteBuffer::
|
||||
ld bc, SPRITEBUFFERSIZE
|
||||
.nextByteLoop
|
||||
xor a
|
||||
ld [hli], a
|
||||
dec bc
|
||||
ld a, b
|
||||
or c
|
||||
jr nz, .nextByteLoop
|
||||
ret
|
||||
|
||||
; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2
|
||||
; in the resulting sprite, the rows of the two source sprites are interlaced
|
||||
; de: output address
|
||||
InterlaceMergeSpriteBuffers::
|
||||
xor a
|
||||
ld [$4000], a
|
||||
call ReadNextInputBit
|
||||
sla c
|
||||
or c ; read next two bits into c
|
||||
and a
|
||||
jr z, .readRLEncodedZeros ; 00 -> RLEncoded zeroes following
|
||||
call WriteSpriteBitsToBuffer ; otherwise write input to output and repeat
|
||||
call MoveToNextBufferPosition
|
||||
jr .readNextInput
|
||||
.readRLEncodedZeros
|
||||
ld c, $0 ; number of zeroes it length encoded, the number
|
||||
.countConsecutiveOnesLoop ; of consecutive ones determines the number of bits the number has
|
||||
call ReadNextInputBit
|
||||
and a
|
||||
jr z, .countConsecutiveOnesFinished
|
||||
inc c
|
||||
jr .countConsecutiveOnesLoop
|
||||
.countConsecutiveOnesFinished
|
||||
ld a, c
|
||||
add a
|
||||
ld hl, LengthEncodingOffsetList
|
||||
add l
|
||||
ld l, a
|
||||
jr nc, .noCarry
|
||||
inc h
|
||||
.noCarry
|
||||
ld a, [hli] ; read offset that is added to the number later on
|
||||
ld e, a ; adding an offset of 2^length - 1 makes every integer uniquely
|
||||
ld d, [hl] ; representable in the length encoding and saves bits
|
||||
push de
|
||||
ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
|
||||
ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
|
||||
ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
|
||||
ld a, SPRITEBUFFERSIZE/2 ; $c4
|
||||
ld [hSpriteInterlaceCounter], a
|
||||
.interlaceLoop
|
||||
ld a, [de]
|
||||
inc c
|
||||
ld e, $0
|
||||
ld d, e
|
||||
.readNumberOfZerosLoop ; reads the next c+1 bits of input
|
||||
call ReadNextInputBit
|
||||
or e
|
||||
ld e, a
|
||||
dec c
|
||||
jr z, .readNumberOfZerosDone
|
||||
sla e
|
||||
rl d
|
||||
jr .readNumberOfZerosLoop
|
||||
.readNumberOfZerosDone
|
||||
pop hl ; add the offset
|
||||
add hl, de
|
||||
ld e, l
|
||||
ld d, h
|
||||
.writeZerosLoop
|
||||
ld b, e
|
||||
xor a ; write 00 to buffer
|
||||
call WriteSpriteBitsToBuffer
|
||||
ld e, b
|
||||
call MoveToNextBufferPosition
|
||||
dec de
|
||||
ld [hld], a ; write byte of source 2
|
||||
ld a, [bc]
|
||||
dec bc
|
||||
ld [hld], a ; write byte of source 1
|
||||
ld a, [de]
|
||||
dec de
|
||||
ld [hld], a ; write byte of source 2
|
||||
ld a, [bc]
|
||||
dec bc
|
||||
ld [hld], a ; write byte of source 1
|
||||
ld a, [hSpriteInterlaceCounter]
|
||||
ld a, d
|
||||
and a
|
||||
jr nz, .continueLoop
|
||||
ld a, e
|
||||
and a
|
||||
.continueLoop
|
||||
jr nz, .writeZerosLoop
|
||||
jr .readNextInput
|
||||
|
||||
; moves output pointer to next position
|
||||
; also cancels the calling function if the all output is done (by removing the return pointer from stack)
|
||||
; and calls postprocessing functions according to the unpack mode
|
||||
MoveToNextBufferPosition::
|
||||
ld a, [wSpriteHeight]
|
||||
ld b, a
|
||||
ld a, [wSpriteCurPosY]
|
||||
inc a
|
||||
cp b
|
||||
jr z, .curColumnDone
|
||||
ld [wSpriteCurPosY], a
|
||||
ld a, [wSpriteOutputPtr]
|
||||
inc a
|
||||
ld [wSpriteOutputPtr], a
|
||||
ret nz
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
inc a
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ret
|
||||
.curColumnDone
|
||||
xor a
|
||||
ld [wSpriteCurPosY], a
|
||||
ld a, [wSpriteOutputBitOffset]
|
||||
and a
|
||||
jr z, .bitOffsetsDone
|
||||
dec a
|
||||
ld [hSpriteInterlaceCounter], a
|
||||
jr nz, .interlaceLoop
|
||||
ld [wSpriteOutputBitOffset], a
|
||||
ld hl, wSpriteOutputPtrCached
|
||||
ld a, [hli]
|
||||
ld [wSpriteOutputPtr], a
|
||||
ld a, [hl]
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ret
|
||||
.bitOffsetsDone
|
||||
ld a, $3
|
||||
ld [wSpriteOutputBitOffset], a
|
||||
ld a, [wSpriteCurPosX]
|
||||
add $8
|
||||
ld [wSpriteCurPosX], a
|
||||
ld b, a
|
||||
ld a, [wSpriteWidth]
|
||||
cp b
|
||||
jr z, .allColumnsDone
|
||||
ld a, [wSpriteOutputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
inc hl
|
||||
jp StoreSpriteOutputPointer
|
||||
.allColumnsDone
|
||||
pop hl
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld a, [wSpriteLoadFlags]
|
||||
bit 1, a
|
||||
jr nz, .done ; test if there is one more sprite to go
|
||||
xor $1
|
||||
set 1, a
|
||||
ld [wSpriteLoadFlags], a
|
||||
jp UncompressSpriteDataLoop
|
||||
.done
|
||||
jp UnpackSprite
|
||||
|
||||
; writes 2 bits (from a) to the output buffer (pointed to from wSpriteOutputPtr)
|
||||
WriteSpriteBitsToBuffer::
|
||||
ld e, a
|
||||
ld a, [wSpriteOutputBitOffset]
|
||||
and a
|
||||
jr z, .offset0
|
||||
cp $2
|
||||
jr c, .offset1
|
||||
jr z, .offset2
|
||||
rrc e ; offset 3
|
||||
rrc e
|
||||
jr .offset0
|
||||
.offset1
|
||||
sla e
|
||||
sla e
|
||||
jr .offset0
|
||||
.offset2
|
||||
swap e
|
||||
.offset0
|
||||
ld a, [wSpriteOutputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
ld a, [hl]
|
||||
or e
|
||||
ld [hl], a
|
||||
ret
|
||||
|
||||
; reads next bit from input stream and returns it in a
|
||||
ReadNextInputBit::
|
||||
ld a, [wSpriteInputBitCounter]
|
||||
dec a
|
||||
jr nz, .curByteHasMoreBitsToRead
|
||||
call ReadNextInputByte
|
||||
ld [wSpriteInputCurByte], a
|
||||
ld a, $8
|
||||
.curByteHasMoreBitsToRead
|
||||
ld [wSpriteInputBitCounter], a
|
||||
ld a, [wSpriteInputCurByte]
|
||||
rlca
|
||||
ld [wSpriteInputCurByte], a
|
||||
and $1
|
||||
ret
|
||||
|
||||
; reads next byte from input stream and returns it in a
|
||||
ReadNextInputByte::
|
||||
ld a, [wSpriteInputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteInputPtr+1]
|
||||
ld h, a
|
||||
ld a, [hli]
|
||||
ld b, a
|
||||
ld a, l
|
||||
ld [wSpriteInputPtr], a
|
||||
ld a, h
|
||||
ld [wSpriteInputPtr+1], a
|
||||
ld a, b
|
||||
ret
|
||||
|
||||
; the nth item is 2^n - 1
|
||||
LengthEncodingOffsetList::
|
||||
dw %0000000000000001
|
||||
dw %0000000000000011
|
||||
dw %0000000000000111
|
||||
dw %0000000000001111
|
||||
dw %0000000000011111
|
||||
dw %0000000000111111
|
||||
dw %0000000001111111
|
||||
dw %0000000011111111
|
||||
dw %0000000111111111
|
||||
dw %0000001111111111
|
||||
dw %0000011111111111
|
||||
dw %0000111111111111
|
||||
dw %0001111111111111
|
||||
dw %0011111111111111
|
||||
dw %0111111111111111
|
||||
dw %1111111111111111
|
||||
|
||||
; unpacks the sprite data depending on the unpack mode
|
||||
UnpackSprite::
|
||||
ld a, [wSpriteUnpackMode]
|
||||
cp $2
|
||||
jp z, UnpackSpriteMode2
|
||||
and a
|
||||
jp nz, XorSpriteChunks
|
||||
ld hl, sSpriteBuffer1
|
||||
call SpriteDifferentialDecode
|
||||
ld hl, sSpriteBuffer2
|
||||
; fall through
|
||||
|
||||
; decodes differential encoded sprite data
|
||||
; input bit value 0 preserves the current bit value and input bit value 1 toggles it (starting from initial value 0).
|
||||
SpriteDifferentialDecode::
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld [wSpriteCurPosY], a
|
||||
call StoreSpriteOutputPointer
|
||||
ld a, [wSpriteFlipped]
|
||||
and a
|
||||
jr z, .notFlipped
|
||||
ld bc, 2*SPRITEBUFFERSIZE
|
||||
ld hl, sSpriteBuffer1
|
||||
.swapLoop
|
||||
swap [hl] ; if flipped swap nybbles in all bytes
|
||||
inc hl
|
||||
dec bc
|
||||
ld a, b
|
||||
or c
|
||||
jr nz, .swapLoop
|
||||
ld hl, DecodeNybble0TableFlipped
|
||||
ld de, DecodeNybble1TableFlipped
|
||||
jr .storeDecodeTablesPointers
|
||||
.notFlipped
|
||||
pop hl
|
||||
ld de, sSpriteBuffer1
|
||||
ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
|
||||
ld a, [hLoadedROMBank]
|
||||
ld hl, DecodeNybble0Table
|
||||
ld de, DecodeNybble1Table
|
||||
.storeDecodeTablesPointers
|
||||
ld a, l
|
||||
ld [wSpriteDecodeTable0Ptr], a
|
||||
ld a, h
|
||||
ld [wSpriteDecodeTable0Ptr+1], a
|
||||
ld a, e
|
||||
ld [wSpriteDecodeTable1Ptr], a
|
||||
ld a, d
|
||||
ld [wSpriteDecodeTable1Ptr+1], a
|
||||
ld e, $0 ; last decoded nybble, initialized to 0
|
||||
.decodeNextByteLoop
|
||||
ld a, [wSpriteOutputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
ld a, [hl]
|
||||
ld b, a
|
||||
jp CopyVideoData
|
||||
swap a
|
||||
and $f
|
||||
call DifferentialDecodeNybble ; decode high nybble
|
||||
swap a
|
||||
ld d, a
|
||||
ld a, b
|
||||
and $f
|
||||
call DifferentialDecodeNybble ; decode low nybble
|
||||
or d
|
||||
ld b, a
|
||||
ld a, [wSpriteOutputPtr]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
ld a, b
|
||||
ld [hl], a ; write back decoded data
|
||||
ld a, [wSpriteHeight]
|
||||
add l ; move on to next column
|
||||
jr nc, .noCarry
|
||||
inc h
|
||||
.noCarry
|
||||
ld [wSpriteOutputPtr], a
|
||||
ld a, h
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ld a, [wSpriteCurPosX]
|
||||
add $8
|
||||
ld [wSpriteCurPosX], a
|
||||
ld b, a
|
||||
ld a, [wSpriteWidth]
|
||||
cp b
|
||||
jr nz, .decodeNextByteLoop ; test if current row is done
|
||||
xor a
|
||||
ld e, a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld a, [wSpriteCurPosY] ; move on to next row
|
||||
inc a
|
||||
ld [wSpriteCurPosY], a
|
||||
ld b, a
|
||||
ld a, [wSpriteHeight]
|
||||
cp b
|
||||
jr z, .done ; test if all rows finished
|
||||
ld a, [wSpriteOutputPtrCached]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtrCached+1]
|
||||
ld h, a
|
||||
inc hl
|
||||
call StoreSpriteOutputPointer
|
||||
jr .decodeNextByteLoop
|
||||
.done
|
||||
xor a
|
||||
ld [wSpriteCurPosY], a
|
||||
ret
|
||||
|
||||
; decodes the nybble stored in a. Last decoded data is assumed to be in e (needed to determine if initial value is 0 or 1)
|
||||
DifferentialDecodeNybble::
|
||||
srl a ; c=a%2, a/=2
|
||||
ld c, $0
|
||||
jr nc, .evenNumber
|
||||
ld c, $1
|
||||
.evenNumber
|
||||
ld l, a
|
||||
ld a, [wSpriteFlipped]
|
||||
and a
|
||||
jr z, .notFlipped ; determine if initial value is 0 or one
|
||||
bit 3, e ; if flipped, consider MSB of last data
|
||||
jr .selectLookupTable
|
||||
.notFlipped
|
||||
bit 0, e ; else consider LSB
|
||||
.selectLookupTable
|
||||
ld e, l
|
||||
jr nz, .initialValue1 ; load the appropriate table
|
||||
ld a, [wSpriteDecodeTable0Ptr]
|
||||
ld l, a
|
||||
ld a, [wSpriteDecodeTable0Ptr+1]
|
||||
jr .tableLookup
|
||||
.initialValue1
|
||||
ld a, [wSpriteDecodeTable1Ptr]
|
||||
ld l, a
|
||||
ld a, [wSpriteDecodeTable1Ptr+1]
|
||||
.tableLookup
|
||||
ld h, a
|
||||
ld a, e
|
||||
add l
|
||||
ld l, a
|
||||
jr nc, .noCarry
|
||||
inc h
|
||||
.noCarry
|
||||
ld a, [hl]
|
||||
bit 0, c
|
||||
jr nz, .selectLowNybble
|
||||
swap a ; select high nybble
|
||||
.selectLowNybble
|
||||
and $f
|
||||
ld e, a ; update last decoded data
|
||||
ret
|
||||
|
||||
DecodeNybble0Table::
|
||||
dn $0, $1
|
||||
dn $3, $2
|
||||
dn $7, $6
|
||||
dn $4, $5
|
||||
dn $f, $e
|
||||
dn $c, $d
|
||||
dn $8, $9
|
||||
dn $b, $a
|
||||
DecodeNybble1Table::
|
||||
dn $f, $e
|
||||
dn $c, $d
|
||||
dn $8, $9
|
||||
dn $b, $a
|
||||
dn $0, $1
|
||||
dn $3, $2
|
||||
dn $7, $6
|
||||
dn $4, $5
|
||||
DecodeNybble0TableFlipped::
|
||||
dn $0, $8
|
||||
dn $c, $4
|
||||
dn $e, $6
|
||||
dn $2, $a
|
||||
dn $f, $7
|
||||
dn $3, $b
|
||||
dn $1, $9
|
||||
dn $d, $5
|
||||
DecodeNybble1TableFlipped::
|
||||
dn $f, $7
|
||||
dn $3, $b
|
||||
dn $1, $9
|
||||
dn $d, $5
|
||||
dn $0, $8
|
||||
dn $c, $4
|
||||
dn $e, $6
|
||||
dn $2, $a
|
||||
|
||||
; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differeintial decoded beforehand.
|
||||
XorSpriteChunks::
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ld [wSpriteCurPosY], a
|
||||
call ResetSpriteBufferPointers
|
||||
ld a, [wSpriteOutputPtr] ; points to buffer 1 or 2, depending on flags
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
call SpriteDifferentialDecode ; decode buffer 1 or 2, depending on flags
|
||||
call ResetSpriteBufferPointers
|
||||
ld a, [wSpriteOutputPtr] ; source buffer, points to buffer 1 or 2, depending on flags
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtr+1]
|
||||
ld h, a
|
||||
ld a, [wSpriteOutputPtrCached] ; destination buffer, points to buffer 2 or 1, depending on flags
|
||||
ld e, a
|
||||
ld a, [wSpriteOutputPtrCached+1]
|
||||
ld d, a
|
||||
.xorChunksLoop
|
||||
ld a, [wSpriteFlipped]
|
||||
and a
|
||||
jr z, .notFlipped
|
||||
push de
|
||||
ld a, [de]
|
||||
ld b, a
|
||||
swap a
|
||||
and $f
|
||||
call ReverseNybble ; if flipped reverse the nybbles in the destination buffer
|
||||
swap a
|
||||
ld c, a
|
||||
ld a, b
|
||||
and $f
|
||||
call ReverseNybble
|
||||
or c
|
||||
pop de
|
||||
ld [de], a
|
||||
.notFlipped
|
||||
ld a, [hli]
|
||||
ld b, a
|
||||
ld a, [de]
|
||||
xor b
|
||||
ld [de], a
|
||||
inc de
|
||||
ld a, [wSpriteCurPosY]
|
||||
inc a
|
||||
ld [wSpriteCurPosY], a ; go to next row
|
||||
ld b, a
|
||||
ld a, [wSpriteHeight]
|
||||
cp b
|
||||
jr nz, .xorChunksLoop ; test if column finished
|
||||
xor a
|
||||
ld [wSpriteCurPosY], a
|
||||
ld a, [wSpriteCurPosX]
|
||||
add $8
|
||||
ld [wSpriteCurPosX], a ; go to next column
|
||||
ld b, a
|
||||
ld a, [wSpriteWidth]
|
||||
cp b
|
||||
jr nz, .xorChunksLoop ; test if all columns finished
|
||||
xor a
|
||||
ld [wSpriteCurPosX], a
|
||||
ret
|
||||
|
||||
; reverses the bits in the nybble given in register a
|
||||
ReverseNybble::
|
||||
ld de, NybbleReverseTable
|
||||
add e
|
||||
ld e, a
|
||||
jr nc, .noCarry
|
||||
inc d
|
||||
.noCarry
|
||||
ld a, [de]
|
||||
ret
|
||||
|
||||
; resets sprite buffer pointers to buffer 1 and 2, depending on wSpriteLoadFlags
|
||||
ResetSpriteBufferPointers::
|
||||
ld a, [wSpriteLoadFlags]
|
||||
bit 0, a
|
||||
jr nz, .buffer2Selected
|
||||
ld de, sSpriteBuffer1
|
||||
ld hl, sSpriteBuffer2
|
||||
jr .storeBufferPointers
|
||||
.buffer2Selected
|
||||
ld de, sSpriteBuffer2
|
||||
ld hl, sSpriteBuffer1
|
||||
.storeBufferPointers
|
||||
ld a, l
|
||||
ld [wSpriteOutputPtr], a
|
||||
ld a, h
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ld a, e
|
||||
ld [wSpriteOutputPtrCached], a
|
||||
ld a, d
|
||||
ld [wSpriteOutputPtrCached+1], a
|
||||
ret
|
||||
|
||||
; maps each nybble to its reverse
|
||||
NybbleReverseTable::
|
||||
db $0, $8, $4, $c, $2, $a, $6 ,$e, $1, $9, $5, $d, $3, $b, $7 ,$f
|
||||
|
||||
; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differeintial decoded beforehand.
|
||||
UnpackSpriteMode2::
|
||||
call ResetSpriteBufferPointers
|
||||
ld a, [wSpriteFlipped]
|
||||
push af
|
||||
xor a
|
||||
ld [wSpriteFlipped], a ; temporarily clear flipped flag for decoding the destination chunk
|
||||
ld a, [wSpriteOutputPtrCached]
|
||||
ld l, a
|
||||
ld a, [wSpriteOutputPtrCached+1]
|
||||
ld h, a
|
||||
call SpriteDifferentialDecode
|
||||
call ResetSpriteBufferPointers
|
||||
pop af
|
||||
ld [wSpriteFlipped], a
|
||||
jp XorSpriteChunks
|
||||
|
||||
; stores hl into the output pointers
|
||||
StoreSpriteOutputPointer::
|
||||
ld a, l
|
||||
ld [wSpriteOutputPtr], a
|
||||
ld [wSpriteOutputPtrCached], a
|
||||
ld a, h
|
||||
ld [wSpriteOutputPtr+1], a
|
||||
ld [wSpriteOutputPtrCached+1], a
|
||||
ret
|
||||
|
|
Loading…
Reference in a new issue