shithub: pokecrystal

Download patch

ref: ec66551519195ee81176b7a07d5fb6871d96112d
parent: 4bc2564a6b217ef269c7c763b98fc4fb41967a97
author: yenatch <yenatch@gmail.com>
date: Sat Feb 2 03:00:50 EST 2013

Decompression function

--- a/main.asm
+++ b/main.asm
@@ -1200,7 +1200,377 @@
 	ret
 ; a1b
 
-INCBIN "baserom.gbc",$a1b,$c2f - $a1b
+INCBIN "baserom.gbc",$a1b,$b40 - $a1b
+
+FarDecompress: ; b40
+; Decompress graphics data at a:hl to de
+
+; put a away for a sec
+	ld [$c2c4], a
+; save bank
+	ld a, [$ff9d]
+	push af
+; bankswitch
+	ld a, [$c2c4]
+	rst Bankswitch
+	
+; what we came here for
+	call Decompress
+	
+; restore bank
+	pop af
+	rst Bankswitch
+	ret
+; b50
+
+
+Decompress: ; b50
+; Pokemon Crystal uses an lz variant for compression.
+
+; This is mainly used for graphics, but the intro's
+; tilemaps also use this compression.
+
+; This function decompresses lz-compressed data at hl to de.
+
+
+; Basic rundown:
+
+;	A typical control command consists of:
+;		-the command (bits 5-7)
+;		-the count (bits 0-4)
+;		-and any additional params
+
+;	$ff is used as a terminator.
+
+
+;	Commands:
+
+;		0: literal
+;			literal data for some number of bytes
+;		1: iterate
+;			one byte repeated for some number of bytes
+;		2: alternate
+;			two bytes alternated for some number of bytes
+;		3: zero (whitespace)
+;			0x00 repeated for some number of bytes
+
+;	Repeater control commands have a signed parameter used to determine the start point.
+;	Wraparound is simulated:
+;		Positive values are added to the start address of the decompressed data
+;		and negative values are subtracted from the current position.
+
+;		4: repeat
+;			repeat some number of bytes from decompressed data
+;		5: flipped
+;			repeat some number of flipped bytes from decompressed data
+;			ex: $ad = %10101101 -> %10110101 = $b5
+;		6: reverse
+;			repeat some number of bytes in reverse from decompressed data
+
+;	If the value in the count needs to be larger than 5 bits,
+;	control code 7 can be used to expand the count to 10 bits.
+
+;		A new control command is read in bits 2-4.
+;		The new 10-bit count is split:
+;			bits 0-1 contain the top 2 bits
+;			another byte is added containing the latter 8
+
+;		So, the structure of the control command becomes:
+;			111xxxyy yyyyyyyy
+;			 |  |  |    |
+;            |  | our new count
+;            | the control command for this count
+;            7 (this command)
+
+; For more information, refer to the code below and in extras/gfx.py .
+
+; save starting output address
+	ld a, e
+	ld [$c2c2], a
+	ld a, d
+	ld [$c2c3], a
+	
+.loop
+; get next byte
+	ld a, [hl]
+; done?
+	cp $ff ; end
+	ret z
+
+; get control code
+	and %11100000
+	
+; 10-bit param?
+	cp $e0 ; LZ_HI
+	jr nz, .normal
+	
+	
+; 10-bit param:
+
+; get next 3 bits (%00011100)
+	ld a, [hl]
+	add a
+	add a ; << 3
+	add a
+	
+; this is our new control code
+	and %11100000
+	push af
+	
+; get param hi
+	ld a, [hli]
+	and %00000011
+	ld b, a
+	
+; get param lo
+	ld a, [hli]
+	ld c, a
+	
+; read at least 1 byte
+	inc bc
+	jr .readers
+	
+	
+.normal
+; push control code
+	push af
+; get param
+	ld a, [hli]
+	and %00011111
+	ld c, a
+	ld b, $0
+; read at least 1 byte
+	inc c
+	
+.readers
+; let's get started
+
+; inc loop counts since we bail as soon as they hit 0
+	inc b
+	inc c
+	
+; get control code
+	pop af
+; command type
+	bit 7, a ; 80, a0, c0
+	jr nz, .repeatertype
+	
+; literals
+	cp $20 ; LZ_ITER
+	jr z, .iter
+	cp $40 ; LZ_ALT
+	jr z, .alt
+	cp $60 ; LZ_ZERO
+	jr z, .zero
+	; else $00
+	
+; 00 ; LZ_LIT
+; literal data for bc bytes
+.loop1
+; done?
+	dec c
+	jr nz, .next1
+	dec b
+	jp z, .loop
+	
+.next1
+	ld a, [hli]
+	ld [de], a
+	inc de
+	jr .loop1
+	
+	
+; 20 ; LZ_ITER
+; write byte for bc bytes
+.iter
+	ld a, [hli]
+	
+.iterloop
+	dec c
+	jr nz, .iternext
+	dec b
+	jp z, .loop
+	
+.iternext
+	ld [de], a
+	inc de
+	jr .iterloop
+	
+	
+; 40 ; LZ_ALT
+; alternate two bytes for bc bytes
+
+; next pair
+.alt
+; done?
+	dec c
+	jr nz, .alt0
+	dec b
+	jp z, .altclose0
+	
+; alternate for bc
+.alt0
+	ld a, [hli]
+	ld [de], a
+	inc de
+	dec c
+	jr nz, .alt1
+; done?
+	dec b
+	jp z, .altclose1
+.alt1
+	ld a, [hld]
+	ld [de], a
+	inc de
+	jr .alt
+	
+; skip past the bytes we were alternating
+.altclose0
+	inc hl
+.altclose1
+	inc hl
+	jr .loop
+	
+	
+; 60 ; LZ_ZERO
+; write 00 for bc bytes
+.zero
+	xor a
+	
+.zeroloop
+	dec c
+	jr nz, .zeronext
+	dec b
+	jp z, .loop
+	
+.zeronext
+	ld [de], a
+	inc de
+	jr .zeroloop
+	
+	
+; repeats
+; 80, a0, c0
+; repeat decompressed data from output
+.repeatertype
+	push hl
+	push af
+; get next byte
+	ld a, [hli]
+; absolute?
+	bit 7, a
+	jr z, .absolute
+	
+; relative
+; a = -a
+	and %01111111 ; forget the bit we just looked at
+	cpl
+; add de (current output address)
+	add e
+	ld l, a
+	ld a, $ff ; -1
+	adc d
+	ld h, a
+	jr .repeaters
+	
+.absolute
+; get next byte (lo)
+	ld l, [hl]
+; last byte (hi)
+	ld h, a
+; add starting output address
+	ld a, [$c2c2]
+	add l
+	ld l, a
+	ld a, [$c2c3]
+	adc h
+	ld h, a
+	
+.repeaters
+	pop af
+	cp $80 ; LZ_REPEAT
+	jr z, .repeat
+	cp $a0 ; LZ_FLIP
+	jr z, .flip
+	cp $c0 ; LZ_REVERSE
+	jr z, .reverse
+	
+; e0 -> 80
+	
+; 80 ; LZ_REPEAT
+; repeat some decompressed data
+.repeat
+; done?
+	dec c
+	jr nz, .repeatnext
+	dec b
+	jr z, .cleanup
+	
+.repeatnext
+	ld a, [hli]
+	ld [de], a
+	inc de
+	jr .repeat
+	
+	
+; a0 ; LZ_FLIP
+; repeat some decompressed data w/ flipped bit order
+.flip
+	dec c
+	jr nz, .flipnext
+	dec b
+	jp z, .cleanup
+	
+.flipnext
+	ld a, [hli]
+	push bc
+	ld bc, $0008
+	
+.fliploop
+	rra
+	rl b
+	dec c
+	jr nz, .fliploop
+	ld a, b
+	pop bc
+	ld [de], a
+	inc de
+	jr .flip
+	
+	
+; c0 ; LZ_REVERSE
+; repeat some decompressed data in reverse
+.reverse
+	dec c
+	jr nz, .reversenext
+	
+	dec b
+	jp z, .cleanup
+	
+.reversenext
+	ld a, [hld]
+	ld [de], a
+	inc de
+	jr .reverse
+	
+	
+.cleanup
+; get type of repeat we just used
+	pop hl
+; was it relative or absolute?
+	bit 7, [hl]
+	jr nz, .next
+
+; skip two bytes for absolute
+	inc hl
+; skip one byte for relative
+.next
+	inc hl
+	jp .loop
+; c2f
+
+
+
 
 UpdatePalsIfCGB: ; c2f
 ; update bgp data from BGPals
--