pic.asm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. ; bankswitches and runs _UncompressSpriteData
  2. ; bank is given in a, sprite input stream is pointed to in wSpriteInputPtr
  3. UncompressSpriteData::
  4. ld b, a
  5. ld a, [H_LOADEDROMBANK]
  6. push af
  7. ld a, b
  8. ld [H_LOADEDROMBANK], a
  9. ld [MBC1RomBank], a
  10. ld a, SRAM_ENABLE
  11. ld [MBC1SRamEnable], a
  12. xor a
  13. ld [MBC1SRamBank], a
  14. call _UncompressSpriteData
  15. pop af
  16. ld [H_LOADEDROMBANK], a
  17. ld [MBC1RomBank], a
  18. ret
  19. ; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
  20. _UncompressSpriteData::
  21. ld hl, sSpriteBuffer1
  22. ld c, (2*SPRITEBUFFERSIZE) % $100
  23. ld b, (2*SPRITEBUFFERSIZE) / $100
  24. xor a
  25. call FillMemory ; clear sprite buffer 1 and 2
  26. ld a, $1
  27. ld [wSpriteInputBitCounter], a
  28. ld a, $3
  29. ld [wSpriteOutputBitOffset], a
  30. xor a
  31. ld [wSpriteCurPosX], a
  32. ld [wSpriteCurPosY], a
  33. ld [wSpriteLoadFlags], a
  34. call ReadNextInputByte ; first byte of input determines sprite width (high nybble) and height (low nybble) in tiles (8x8 pixels)
  35. ld b, a
  36. and $f
  37. add a
  38. add a
  39. add a
  40. ld [wSpriteHeight], a
  41. ld a, b
  42. swap a
  43. and $f
  44. add a
  45. add a
  46. add a
  47. ld [wSpriteWidth], a
  48. call ReadNextInputBit
  49. ld [wSpriteLoadFlags], a ; initialite bit1 to 0 and bit0 to the first input bit
  50. ; this will load two chunks of data to sSpriteBuffer1 and sSpriteBuffer2
  51. ; bit 0 decides in which one the first chunk is placed
  52. ; fall through
  53. ; uncompresses a chunk from the sprite input data stream (pointed to at wd0da) into sSpriteBuffer1 or sSpriteBuffer2
  54. ; each chunk is a 1bpp sprite. A 2bpp sprite consist of two chunks which are merged afterwards
  55. ; note that this is an endless loop which is terminated during a call to MoveToNextBufferPosition by manipulating the stack
  56. UncompressSpriteDataLoop::
  57. ld hl, sSpriteBuffer1
  58. ld a, [wSpriteLoadFlags]
  59. bit 0, a
  60. jr z, .useSpriteBuffer1 ; check which buffer to use
  61. ld hl, sSpriteBuffer2
  62. .useSpriteBuffer1
  63. call StoreSpriteOutputPointer
  64. ld a, [wSpriteLoadFlags]
  65. bit 1, a
  66. jr z, .startDecompression ; check if last iteration
  67. call ReadNextInputBit ; if last chunk, read 1-2 bit unpacking mode
  68. and a
  69. jr z, .unpackingMode0 ; 0 -> mode 0
  70. call ReadNextInputBit ; 1 0 -> mode 1
  71. inc a ; 1 1 -> mode 2
  72. .unpackingMode0
  73. ld [wSpriteUnpackMode], a
  74. .startDecompression
  75. call ReadNextInputBit
  76. and a
  77. jr z, .readRLEncodedZeros ; if first bit is 0, the input starts with zeroes, otherwise with (non-zero) input
  78. .readNextInput
  79. call ReadNextInputBit
  80. ld c, a
  81. call ReadNextInputBit
  82. sla c
  83. or c ; read next two bits into c
  84. and a
  85. jr z, .readRLEncodedZeros ; 00 -> RLEncoded zeroes following
  86. call WriteSpriteBitsToBuffer ; otherwise write input to output and repeat
  87. call MoveToNextBufferPosition
  88. jr .readNextInput
  89. .readRLEncodedZeros
  90. ld c, $0 ; number of zeroes it length encoded, the number
  91. .countConsecutiveOnesLoop ; of consecutive ones determines the number of bits the number has
  92. call ReadNextInputBit
  93. and a
  94. jr z, .countConsecutiveOnesFinished
  95. inc c
  96. jr .countConsecutiveOnesLoop
  97. .countConsecutiveOnesFinished
  98. ld a, c
  99. add a
  100. ld hl, LengthEncodingOffsetList
  101. add l
  102. ld l, a
  103. jr nc, .noCarry
  104. inc h
  105. .noCarry
  106. ld a, [hli] ; read offset that is added to the number later on
  107. ld e, a ; adding an offset of 2^length - 1 makes every integer uniquely
  108. ld d, [hl] ; representable in the length encoding and saves bits
  109. push de
  110. inc c
  111. ld e, $0
  112. ld d, e
  113. .readNumberOfZerosLoop ; reads the next c+1 bits of input
  114. call ReadNextInputBit
  115. or e
  116. ld e, a
  117. dec c
  118. jr z, .readNumberOfZerosDone
  119. sla e
  120. rl d
  121. jr .readNumberOfZerosLoop
  122. .readNumberOfZerosDone
  123. pop hl ; add the offset
  124. add hl, de
  125. ld e, l
  126. ld d, h
  127. .writeZerosLoop
  128. ld b, e
  129. xor a ; write 00 to buffer
  130. call WriteSpriteBitsToBuffer
  131. ld e, b
  132. call MoveToNextBufferPosition
  133. dec de
  134. ld a, d
  135. and a
  136. jr nz, .continueLoop
  137. ld a, e
  138. and a
  139. .continueLoop
  140. jr nz, .writeZerosLoop
  141. jr .readNextInput
  142. ; moves output pointer to next position
  143. ; also cancels the calling function if the all output is done (by removing the return pointer from stack)
  144. ; and calls postprocessing functions according to the unpack mode
  145. MoveToNextBufferPosition::
  146. ld a, [wSpriteHeight]
  147. ld b, a
  148. ld a, [wSpriteCurPosY]
  149. inc a
  150. cp b
  151. jr z, .curColumnDone
  152. ld [wSpriteCurPosY], a
  153. ld a, [wSpriteOutputPtr]
  154. inc a
  155. ld [wSpriteOutputPtr], a
  156. ret nz
  157. ld a, [wSpriteOutputPtr+1]
  158. inc a
  159. ld [wSpriteOutputPtr+1], a
  160. ret
  161. .curColumnDone
  162. xor a
  163. ld [wSpriteCurPosY], a
  164. ld a, [wSpriteOutputBitOffset]
  165. and a
  166. jr z, .bitOffsetsDone
  167. dec a
  168. ld [wSpriteOutputBitOffset], a
  169. ld hl, wSpriteOutputPtrCached
  170. ld a, [hli]
  171. ld [wSpriteOutputPtr], a
  172. ld a, [hl]
  173. ld [wSpriteOutputPtr+1], a
  174. ret
  175. .bitOffsetsDone
  176. ld a, $3
  177. ld [wSpriteOutputBitOffset], a
  178. ld a, [wSpriteCurPosX]
  179. add $8
  180. ld [wSpriteCurPosX], a
  181. ld b, a
  182. ld a, [wSpriteWidth]
  183. cp b
  184. jr z, .allColumnsDone
  185. ld a, [wSpriteOutputPtr]
  186. ld l, a
  187. ld a, [wSpriteOutputPtr+1]
  188. ld h, a
  189. inc hl
  190. jp StoreSpriteOutputPointer
  191. .allColumnsDone
  192. pop hl
  193. xor a
  194. ld [wSpriteCurPosX], a
  195. ld a, [wSpriteLoadFlags]
  196. bit 1, a
  197. jr nz, .done ; test if there is one more sprite to go
  198. xor $1
  199. set 1, a
  200. ld [wSpriteLoadFlags], a
  201. jp UncompressSpriteDataLoop
  202. .done
  203. jp UnpackSprite
  204. ; writes 2 bits (from a) to the output buffer (pointed to from wSpriteOutputPtr)
  205. WriteSpriteBitsToBuffer::
  206. ld e, a
  207. ld a, [wSpriteOutputBitOffset]
  208. and a
  209. jr z, .offset0
  210. cp $2
  211. jr c, .offset1
  212. jr z, .offset2
  213. rrc e ; offset 3
  214. rrc e
  215. jr .offset0
  216. .offset1
  217. sla e
  218. sla e
  219. jr .offset0
  220. .offset2
  221. swap e
  222. .offset0
  223. ld a, [wSpriteOutputPtr]
  224. ld l, a
  225. ld a, [wSpriteOutputPtr+1]
  226. ld h, a
  227. ld a, [hl]
  228. or e
  229. ld [hl], a
  230. ret
  231. ; reads next bit from input stream and returns it in a
  232. ReadNextInputBit::
  233. ld a, [wSpriteInputBitCounter]
  234. dec a
  235. jr nz, .curByteHasMoreBitsToRead
  236. call ReadNextInputByte
  237. ld [wSpriteInputCurByte], a
  238. ld a, $8
  239. .curByteHasMoreBitsToRead
  240. ld [wSpriteInputBitCounter], a
  241. ld a, [wSpriteInputCurByte]
  242. rlca
  243. ld [wSpriteInputCurByte], a
  244. and $1
  245. ret
  246. ; reads next byte from input stream and returns it in a
  247. ReadNextInputByte::
  248. ld a, [wSpriteInputPtr]
  249. ld l, a
  250. ld a, [wSpriteInputPtr+1]
  251. ld h, a
  252. ld a, [hli]
  253. ld b, a
  254. ld a, l
  255. ld [wSpriteInputPtr], a
  256. ld a, h
  257. ld [wSpriteInputPtr+1], a
  258. ld a, b
  259. ret
  260. ; the nth item is 2^n - 1
  261. LengthEncodingOffsetList::
  262. dw %0000000000000001
  263. dw %0000000000000011
  264. dw %0000000000000111
  265. dw %0000000000001111
  266. dw %0000000000011111
  267. dw %0000000000111111
  268. dw %0000000001111111
  269. dw %0000000011111111
  270. dw %0000000111111111
  271. dw %0000001111111111
  272. dw %0000011111111111
  273. dw %0000111111111111
  274. dw %0001111111111111
  275. dw %0011111111111111
  276. dw %0111111111111111
  277. dw %1111111111111111
  278. ; unpacks the sprite data depending on the unpack mode
  279. UnpackSprite::
  280. ld a, [wSpriteUnpackMode]
  281. cp $2
  282. jp z, UnpackSpriteMode2
  283. and a
  284. jp nz, XorSpriteChunks
  285. ld hl, sSpriteBuffer1
  286. call SpriteDifferentialDecode
  287. ld hl, sSpriteBuffer2
  288. ; fall through
  289. ; decodes differential encoded sprite data
  290. ; input bit value 0 preserves the current bit value and input bit value 1 toggles it (starting from initial value 0).
  291. SpriteDifferentialDecode::
  292. xor a
  293. ld [wSpriteCurPosX], a
  294. ld [wSpriteCurPosY], a
  295. call StoreSpriteOutputPointer
  296. ld a, [wSpriteFlipped]
  297. and a
  298. jr z, .notFlipped
  299. ld hl, DecodeNybble0TableFlipped
  300. ld de, DecodeNybble1TableFlipped
  301. jr .storeDecodeTablesPointers
  302. .notFlipped
  303. ld hl, DecodeNybble0Table
  304. ld de, DecodeNybble1Table
  305. .storeDecodeTablesPointers
  306. ld a, l
  307. ld [wSpriteDecodeTable0Ptr], a
  308. ld a, h
  309. ld [wSpriteDecodeTable0Ptr+1], a
  310. ld a, e
  311. ld [wSpriteDecodeTable1Ptr], a
  312. ld a, d
  313. ld [wSpriteDecodeTable1Ptr+1], a
  314. ld e, $0 ; last decoded nybble, initialized to 0
  315. .decodeNextByteLoop
  316. ld a, [wSpriteOutputPtr]
  317. ld l, a
  318. ld a, [wSpriteOutputPtr+1]
  319. ld h, a
  320. ld a, [hl]
  321. ld b, a
  322. swap a
  323. and $f
  324. call DifferentialDecodeNybble ; decode high nybble
  325. swap a
  326. ld d, a
  327. ld a, b
  328. and $f
  329. call DifferentialDecodeNybble ; decode low nybble
  330. or d
  331. ld b, a
  332. ld a, [wSpriteOutputPtr]
  333. ld l, a
  334. ld a, [wSpriteOutputPtr+1]
  335. ld h, a
  336. ld a, b
  337. ld [hl], a ; write back decoded data
  338. ld a, [wSpriteHeight]
  339. add l ; move on to next column
  340. jr nc, .noCarry
  341. inc h
  342. .noCarry
  343. ld [wSpriteOutputPtr], a
  344. ld a, h
  345. ld [wSpriteOutputPtr+1], a
  346. ld a, [wSpriteCurPosX]
  347. add $8
  348. ld [wSpriteCurPosX], a
  349. ld b, a
  350. ld a, [wSpriteWidth]
  351. cp b
  352. jr nz, .decodeNextByteLoop ; test if current row is done
  353. xor a
  354. ld e, a
  355. ld [wSpriteCurPosX], a
  356. ld a, [wSpriteCurPosY] ; move on to next row
  357. inc a
  358. ld [wSpriteCurPosY], a
  359. ld b, a
  360. ld a, [wSpriteHeight]
  361. cp b
  362. jr z, .done ; test if all rows finished
  363. ld a, [wSpriteOutputPtrCached]
  364. ld l, a
  365. ld a, [wSpriteOutputPtrCached+1]
  366. ld h, a
  367. inc hl
  368. call StoreSpriteOutputPointer
  369. jr .decodeNextByteLoop
  370. .done
  371. xor a
  372. ld [wSpriteCurPosY], a
  373. ret
  374. ; 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)
  375. DifferentialDecodeNybble::
  376. srl a ; c=a%2, a/=2
  377. ld c, $0
  378. jr nc, .evenNumber
  379. ld c, $1
  380. .evenNumber
  381. ld l, a
  382. ld a, [wSpriteFlipped]
  383. and a
  384. jr z, .notFlipped ; determine if initial value is 0 or one
  385. bit 3, e ; if flipped, consider MSB of last data
  386. jr .selectLookupTable
  387. .notFlipped
  388. bit 0, e ; else consider LSB
  389. .selectLookupTable
  390. ld e, l
  391. jr nz, .initialValue1 ; load the appropriate table
  392. ld a, [wSpriteDecodeTable0Ptr]
  393. ld l, a
  394. ld a, [wSpriteDecodeTable0Ptr+1]
  395. jr .tableLookup
  396. .initialValue1
  397. ld a, [wSpriteDecodeTable1Ptr]
  398. ld l, a
  399. ld a, [wSpriteDecodeTable1Ptr+1]
  400. .tableLookup
  401. ld h, a
  402. ld a, e
  403. add l
  404. ld l, a
  405. jr nc, .noCarry
  406. inc h
  407. .noCarry
  408. ld a, [hl]
  409. bit 0, c
  410. jr nz, .selectLowNybble
  411. swap a ; select high nybble
  412. .selectLowNybble
  413. and $f
  414. ld e, a ; update last decoded data
  415. ret
  416. DecodeNybble0Table::
  417. dn $0, $1
  418. dn $3, $2
  419. dn $7, $6
  420. dn $4, $5
  421. dn $f, $e
  422. dn $c, $d
  423. dn $8, $9
  424. dn $b, $a
  425. DecodeNybble1Table::
  426. dn $f, $e
  427. dn $c, $d
  428. dn $8, $9
  429. dn $b, $a
  430. dn $0, $1
  431. dn $3, $2
  432. dn $7, $6
  433. dn $4, $5
  434. DecodeNybble0TableFlipped::
  435. dn $0, $8
  436. dn $c, $4
  437. dn $e, $6
  438. dn $2, $a
  439. dn $f, $7
  440. dn $3, $b
  441. dn $1, $9
  442. dn $d, $5
  443. DecodeNybble1TableFlipped::
  444. dn $f, $7
  445. dn $3, $b
  446. dn $1, $9
  447. dn $d, $5
  448. dn $0, $8
  449. dn $c, $4
  450. dn $e, $6
  451. dn $2, $a
  452. ; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differeintial decoded beforehand.
  453. XorSpriteChunks::
  454. xor a
  455. ld [wSpriteCurPosX], a
  456. ld [wSpriteCurPosY], a
  457. call ResetSpriteBufferPointers
  458. ld a, [wSpriteOutputPtr] ; points to buffer 1 or 2, depending on flags
  459. ld l, a
  460. ld a, [wSpriteOutputPtr+1]
  461. ld h, a
  462. call SpriteDifferentialDecode ; decode buffer 1 or 2, depending on flags
  463. call ResetSpriteBufferPointers
  464. ld a, [wSpriteOutputPtr] ; source buffer, points to buffer 1 or 2, depending on flags
  465. ld l, a
  466. ld a, [wSpriteOutputPtr+1]
  467. ld h, a
  468. ld a, [wSpriteOutputPtrCached] ; destination buffer, points to buffer 2 or 1, depending on flags
  469. ld e, a
  470. ld a, [wSpriteOutputPtrCached+1]
  471. ld d, a
  472. .xorChunksLoop
  473. ld a, [wSpriteFlipped]
  474. and a
  475. jr z, .notFlipped
  476. push de
  477. ld a, [de]
  478. ld b, a
  479. swap a
  480. and $f
  481. call ReverseNybble ; if flipped reverse the nybbles in the destination buffer
  482. swap a
  483. ld c, a
  484. ld a, b
  485. and $f
  486. call ReverseNybble
  487. or c
  488. pop de
  489. ld [de], a
  490. .notFlipped
  491. ld a, [hli]
  492. ld b, a
  493. ld a, [de]
  494. xor b
  495. ld [de], a
  496. inc de
  497. ld a, [wSpriteCurPosY]
  498. inc a
  499. ld [wSpriteCurPosY], a ; go to next row
  500. ld b, a
  501. ld a, [wSpriteHeight]
  502. cp b
  503. jr nz, .xorChunksLoop ; test if column finished
  504. xor a
  505. ld [wSpriteCurPosY], a
  506. ld a, [wSpriteCurPosX]
  507. add $8
  508. ld [wSpriteCurPosX], a ; go to next column
  509. ld b, a
  510. ld a, [wSpriteWidth]
  511. cp b
  512. jr nz, .xorChunksLoop ; test if all columns finished
  513. xor a
  514. ld [wSpriteCurPosX], a
  515. ret
  516. ; reverses the bits in the nybble given in register a
  517. ReverseNybble::
  518. ld de, NybbleReverseTable
  519. add e
  520. ld e, a
  521. jr nc, .noCarry
  522. inc d
  523. .noCarry
  524. ld a, [de]
  525. ret
  526. ; resets sprite buffer pointers to buffer 1 and 2, depending on wSpriteLoadFlags
  527. ResetSpriteBufferPointers::
  528. ld a, [wSpriteLoadFlags]
  529. bit 0, a
  530. jr nz, .buffer2Selected
  531. ld de, sSpriteBuffer1
  532. ld hl, sSpriteBuffer2
  533. jr .storeBufferPointers
  534. .buffer2Selected
  535. ld de, sSpriteBuffer2
  536. ld hl, sSpriteBuffer1
  537. .storeBufferPointers
  538. ld a, l
  539. ld [wSpriteOutputPtr], a
  540. ld a, h
  541. ld [wSpriteOutputPtr+1], a
  542. ld a, e
  543. ld [wSpriteOutputPtrCached], a
  544. ld a, d
  545. ld [wSpriteOutputPtrCached+1], a
  546. ret
  547. ; maps each nybble to its reverse
  548. NybbleReverseTable::
  549. db $0, $8, $4, $c, $2, $a, $6 ,$e, $1, $9, $5, $d, $3, $b, $7 ,$f
  550. ; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differeintial decoded beforehand.
  551. UnpackSpriteMode2::
  552. call ResetSpriteBufferPointers
  553. ld a, [wSpriteFlipped]
  554. push af
  555. xor a
  556. ld [wSpriteFlipped], a ; temporarily clear flipped flag for decoding the destination chunk
  557. ld a, [wSpriteOutputPtrCached]
  558. ld l, a
  559. ld a, [wSpriteOutputPtrCached+1]
  560. ld h, a
  561. call SpriteDifferentialDecode
  562. call ResetSpriteBufferPointers
  563. pop af
  564. ld [wSpriteFlipped], a
  565. jp XorSpriteChunks
  566. ; stores hl into the output pointers
  567. StoreSpriteOutputPointer::
  568. ld a, l
  569. ld [wSpriteOutputPtr], a
  570. ld [wSpriteOutputPtrCached], a
  571. ld a, h
  572. ld [wSpriteOutputPtr+1], a
  573. ld [wSpriteOutputPtrCached+1], a
  574. ret