1; **************************************************
2; SMSlib - C programming library for the SMS/GG
3; ( part of devkitSMS - github.com/sverx/devkitSMS )
4; **************************************************
5
6INCLUDE "SMSlib_private.inc"
7
8SECTION bss_clib
9SECTION bss_SMSlib
10
11__SMSlib_PSGaidenDecompBufferAddr:
12   defw 0
13
14SECTION code_clib
15SECTION code_SMSlib
16
17PUBLIC asm_SMSlib_loadPSGaidencompressedTiles
18
19asm_SMSlib_loadPSGaidencompressedTiles:
20
21   ; Phantasy Star Gaiden Tile Decoder
22   ; taken from http://www.smspower.org/Development/PhantasyStarGaidenTileDecoder
23
24   ; void SMS_loadPSGaidencompressedTiles (void *src, unsigned int tilefrom)
25   ;
26   ; enter : de = void *src
27   ;         hl = unsigned int tilefrom
28   ;
29   ; uses  : af, bc, de, hl, ix, iy
30
31   add hl,hl
32   add hl,hl
33   add hl,hl
34   add hl,hl
35   add hl,hl
36
37   set 6,h
38   INCLUDE "SMS_CRT0_RST08.inc"
39
40   ld hl,-32
41   add hl,sp
42   ld sp,hl
43
44   ld (__SMSlib_PSGaidenDecompBufferAddr),hl
45
46   ex de,hl
47
48   ld c,(hl)                ; bc = number of tiles
49   inc hl
50   ld b,(hl)
51   inc hl
52
53   push hl                  ; ld ix,hl
54   pop ix
55
56_DecompressTile:
57   push bc                  ; save number of tiles
58     ld b,4                 ; count 4 bitplanes
59     ld de,(__SMSlib_PSGaidenDecompBufferAddr)   ; write to de
60     ld c,(ix)              ; c = encoding information for 4 bitplanes
61     inc ix
62
63_DecompressBitplane:
64     rlc c        ; %0x = all bits either 0 or 1
65     jr nc,_AllTheSame
66     rlc c        ; %11 = raw data
67     jr c,_RawData
68
69_Compressed:
70     ld a,(ix)    ; get method byte
71     inc ix
72
73     ex de,hl     ; get bitplane, if it is referring to one
74     ld d,a
75     and 0x03
76     add a,a      ; calculate address of that bitplane
77     add a,a      ; = buffer + bitplane * 8
78     add a,a
79     ld e,a
80     ld a,d       ; get method byte back
81     ld d,0x00
82     ld iy,(__SMSlib_PSGaidenDecompBufferAddr)
83     add iy,de    ; now iy points to the referred to bitplane
84     ex de,hl
85
86     ; now check the method byte
87     cp 0x03      ; %000000pp
88     jr c,_DuplicateBitplane
89     cp 0x10
90     jr c,_CommonValue
91     cp 0x13      ; %000100pp
92     jr c,_DuplicateBitplaneInvert
93     cp 0x20
94     jr c,_CommonValue
95     cp 0x23      ; %001000pp
96     jr c,_DuplicateBitplanePartial
97     cp 0x40
98     jr c,_CommonValue
99     cp 0x43      ; %010000pp
100     jr c,_DuplicateBitplanePartialInvert
101     ; fall through
102
103_CommonValue:
104     ld h,a       ; h = bitmask
105     ld l,(ix)    ; l = common value
106     inc ix
107     jr _OutputCommonValue
108
109_RawData:
110     ld h,0x00    ; empty bitmask; no common value
111     jr _OutputCommonValue
112
113_AllTheSame:
114     rlc c        ; get next bit into carry
115     sbc a,a      ; will make $00 if carry = 0, $ff if it is 1
116     ld l,a       ; that is the common value
117     ld h,0xff    ; full bitmask
118     ; fall through
119
120_OutputCommonValue:
121     push bc
122       ld b,8       ; loop counter
123_loop1:
124       ld a,l       ; get common value
125       rlc h        ; get bit out of bitmask
126       jr c,_skip1  ; if 1, use the common value
127       ld a,(ix)    ; else get it from (ix++)
128       inc ix
129_skip1:
130       ld (de),a    ; write to dest
131       inc de
132       djnz _loop1  ; loop over 8 bytes
133     pop bc
134   jr _BitplaneDone
135
136_DuplicateBitplane:
137     ld hl,0xff00   ; full copy bitmask, empty inversion bitmask
138     jr _OutputDuplicate
139
140_DuplicateBitplaneInvert:
141     ld hl,0xffff   ; full copy bitmask, full inversion bitmask
142     jr _OutputDuplicate
143
144_DuplicateBitplanePartial:
145     ld h,(ix)    ; get copy bitmask
146     ld l,0x00    ; empty inversion bitmask
147     inc ix
148     jr _OutputDuplicate
149
150_DuplicateBitplanePartialInvert:
151     ld h,(ix)    ; get copy bitmask
152     ld l,0xff    ; full inversion bitmask
153     inc ix
154     ; fall through
155
156_OutputDuplicate:
157     push bc
158       ld b,8      ; loop counter
159_loop2:
160       ld a,(iy)   ; read byte to copy
161       inc iy
162       xor l       ; apply inversion mask
163       rlc h       ; get bit out of bitmask
164       jr c,_skip2 ; if 1, use the copied value
165       ld a,(ix)   ; else get it from (ix++)
166       inc ix
167_skip2:
168       ld (de),a   ; write to dest
169       inc de
170       djnz _loop2 ; loop over 8 bytes
171     pop bc
172     ; fall through
173
174_BitplaneDone:
175     dec b        ; decrement bitplane counter
176     jp nz,_DecompressBitplane ; loop if not zero
177
178_OutputTileToVRAM:
179     ld de,8               ; we are interleaving every 8th byte
180     ld c,e                ; counter for the interleaving run
181     ld hl,(__SMSlib_PSGaidenDecompBufferAddr)  ; point at data to write
182
183_outLoop:
184     ld b,4                ; there are 4 bytes to interleave
185     push hl
186_inLoop:
187       ld a,(hl)            ; read byte
188       out (VDPDataPort),a  ; write to vram
189       add hl,de            ; skip 8 bytes
190       djnz _inLoop
191     pop hl
192     inc hl                ; next interleaving run
193     dec c
194     jr nz,_outLoop
195
196   pop bc
197   dec bc                  ; next tile
198   ld a,b
199   or c
200   jp nz,_DecompressTile
201
202   ld hl,32
203   add hl,sp
204   ld sp,hl
205
206   ret
207