I tried finding other threads about this issue but could only find Bregalad's old thread on his/her custom format https://forums.nesdev.com/viewtopic.php?f=2&t=9724 which seemed a bit too complex for me to dare try implementing.
My take is to cut down the data from 4bytes/tile entry to 3 by taking away a big range from the x and y positions and scattering the bits for the tile character in with the other values like this:
X = x position
Y = y position
T = tile character
A = attributes
Uncompressed data:
Code: Select all
1: XXXX xxxx
2: YYYY yyyy
3: TTTT tttt
4: AAAA aaaa
Code: Select all
1: **XX xxxx
2: **YY yyyy
3: *TTT tttt
4: AAA* **aa
Code: Select all
1: TTXX xxxx
2: TtYY yyyy
3: AAAt ttaa
Code: Select all
; ZP stuff
OAM_sprite_ptr_lo .db 1
OAM_sprite_ptr_hi .db 1
temp_var_1 .db 1
temp_var_2 .db 1
temp_var_3 .db 1
temp_var_4 .db 1
tile_offset .db 1
; drawing routine
DrawMetaSprite:
ldy #0
lda (OAM_sprite_ptr_lo), y
sta OAM_currSpriteByteSize ; this is a value I use unrelated to the compression.
iny
lda (OAM_sprite_ptr_lo), y
sta tile_offset
dey
ldx #0
@drawing_loop:
@temp_x = temp_var_1
@temp_y = temp_var_2
@temp_tile = temp_var_3
@temp_attr = temp_var_4
lda (OAM_sprite_ptr_lo), y
sta @temp_x ; we'll save this for later to do offsets to the x-position.
and #%11000000 ; shave off all but the tile char bits (bit 6-5).
sta @temp_tile ; store them for later.
iny
lda (OAM_sprite_ptr_lo), y
sta @temp_y ; save y-position for later just like the x-position.
and #%11000000 ; shave off all but the tile char bits (bit 4-3).
lsr
lsr ; shift the bits.
ora @temp_tile ; merge with bits 6-5.
sta @temp_tile
; TTTt 0000
iny
lda (OAM_sprite_ptr_lo), y
sta @temp_attr ; save for later.
and #%00011100 ; shave off all but the tile char bits (bit 2-0).
lsr
ora @temp_tile ; shift and merge with the other bits
; TTTt ttt0
lsr ; shift the result once more to get all bits in thei proper place.
; 0TTT tttt
adc tile_offset ; add the offset stored in the header for the metasprite data, incase we're using tiles within $80-$FF.
sta $0201, x ; store the final uncompressed tile char byte.
;;;; Do position offsets, attribute manipulations and so on...
rts
Code: Select all
test_metasprite_offset:
.db -16, -16 ; y, x
test_metasprite_0:
.db 16 ; header: amount of unpacked bytes in this sprite
.db 128 ; ; tile char offset value
.db $88, $08, $1f ;;;; .db $08, $08, $47, $03
.db $90, $48, $03 ;;;; .db $10, $08, $48, $03
.db $88, $90, $1f ;;;; .db $08, $10, $57, $03
.db $90, $d0, $03 ;;;; .db $10, $10, $58, $03
I've implemented all this in my engine now and have it sort of working apart from some issues I have on existing metasprites with values going outside of the range that my compression allows.
I would be very interested in hearing if my take on this makes sense and if there's anything I can do to speed up the decompression of the tile character. My idea with compressing the data this way is that it will not be too hard to understand the decompression code as well as being compatible with metasprites with a maximum width of 63x63 (actually (63+8) * (63+8), given the width and height of an individual tile).
Sorry if this post is hard to follow. I omitted most of my drawing routine to put the focus on the unpacking. Obviously the real code does a lot more in terms of flipping sprites and offsetting positions before finally storing them..
Cheers!