From 9e26691bfd58eb4539bf1111c0f06b99d1245831 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Sun, 11 Jul 2021 22:10:51 -0400 Subject: [PATCH] hgr: sprites: first sprite attempt --- games/mist_hgr/graphics_title/cyan1.vgi | 8 + games/mist_hgr/graphics_title/cyan2.vgi | 21 + graphics/hgr/amiga_ball/Makefile | 51 +++ .../hgr/{sprite => amiga_ball}/apple2_36b.inc | 0 .../{sprite => amiga_ball}/apple2_70_zp.inc | 0 graphics/hgr/{sprite => amiga_ball}/ball.s | 0 graphics/hgr/amiga_ball/hello.bas | 2 + graphics/hgr/{sprite => amiga_ball}/pattern.s | 0 graphics/hgr/{sprite => amiga_ball}/tiny_30.s | 0 graphics/hgr/sprite/Makefile | 41 +- graphics/hgr/sprite/decompress_fast_v2.s | 370 ++++++++++++++++++ graphics/hgr/sprite/graphics/Makefile | 29 ++ graphics/hgr/sprite/graphics/README | 1 + graphics/hgr/sprite/graphics/graphics.inc | 1 + graphics/hgr/sprite/graphics/mona.png | Bin 0 -> 18683 bytes graphics/hgr/sprite/hardware.inc | 71 ++++ graphics/hgr/sprite/hello.bas | 3 +- graphics/hgr/sprite/sprite.s | 296 ++++++++++++++ 18 files changed, 863 insertions(+), 31 deletions(-) create mode 100644 games/mist_hgr/graphics_title/cyan1.vgi create mode 100644 games/mist_hgr/graphics_title/cyan2.vgi create mode 100644 graphics/hgr/amiga_ball/Makefile rename graphics/hgr/{sprite => amiga_ball}/apple2_36b.inc (100%) rename graphics/hgr/{sprite => amiga_ball}/apple2_70_zp.inc (100%) rename graphics/hgr/{sprite => amiga_ball}/ball.s (100%) create mode 100644 graphics/hgr/amiga_ball/hello.bas rename graphics/hgr/{sprite => amiga_ball}/pattern.s (100%) rename graphics/hgr/{sprite => amiga_ball}/tiny_30.s (100%) create mode 100644 graphics/hgr/sprite/decompress_fast_v2.s create mode 100644 graphics/hgr/sprite/graphics/Makefile create mode 100644 graphics/hgr/sprite/graphics/README create mode 100644 graphics/hgr/sprite/graphics/graphics.inc create mode 100644 graphics/hgr/sprite/graphics/mona.png create mode 100644 graphics/hgr/sprite/hardware.inc create mode 100644 graphics/hgr/sprite/sprite.s diff --git a/games/mist_hgr/graphics_title/cyan1.vgi b/games/mist_hgr/graphics_title/cyan1.vgi new file mode 100644 index 00000000..f204cb67 --- /dev/null +++ b/games/mist_hgr/graphics_title/cyan1.vgi @@ -0,0 +1,8 @@ +; Cyan logo 1 +CLS 0x80 ; black2 background +FCIRC 6 140 91 22 ; blue circle +RECT 7 7 118 88 161 95 ; white bar +FCIRC 5 140 82 8 ; orange circle +LINE 4 140 92 129 109 ; left of pyramid +VTRI 4 140 92 145 154 114 ; pyramid +END diff --git a/games/mist_hgr/graphics_title/cyan2.vgi b/games/mist_hgr/graphics_title/cyan2.vgi new file mode 100644 index 00000000..c1082633 --- /dev/null +++ b/games/mist_hgr/graphics_title/cyan2.vgi @@ -0,0 +1,21 @@ +; Cyan logo 2 +FCIRC 7 140 91 22 ; white circle +FCIRC 4 140 91 9 ; black circle +LINE 4 140 91 157 74 ; radius +LINE 4 140 91 159 77 +LINE 4 140 91 161 80 +LINE 6 124 115 122 115 ; C +LINETO 118 118 +LINETO 118 121 +LINETO 122 123 +LINETO 124 123 +LINE 6 131 115 134 121 ; Y +LINETO 134 123 +LINE 6 137 115 134 121 +LINE 6 144 115 140 123 ; A +LINE 6 144 115 148 123 +LINE 6 143 119 147 119 +LINE 6 152 123 152 115 ; N +LINETO 162 123 +LINETO 162 115 +END diff --git a/graphics/hgr/amiga_ball/Makefile b/graphics/hgr/amiga_ball/Makefile new file mode 100644 index 00000000..75e2f8a3 --- /dev/null +++ b/graphics/hgr/amiga_ball/Makefile @@ -0,0 +1,51 @@ +include ../../../Makefile.inc + +DOS33 = ../../../utils/dos33fs-utils/dos33 +TOKENIZE = ../../../utils/asoft_basic-utils/tokenize_asoft +LINKER_SCRIPTS = ../../../linker_scripts +EMPTY_DISK = ../../../empty_disk/empty.dsk + +all: sprite.dsk + +sprite.dsk: HELLO BALL PATTERN TINY + cp $(EMPTY_DISK) sprite.dsk + $(DOS33) -y sprite.dsk SAVE A HELLO + $(DOS33) -y sprite.dsk BSAVE -a 0x0300 BALL + $(DOS33) -y sprite.dsk BSAVE -a 0x036B PATTERN + $(DOS33) -y sprite.dsk BSAVE -a 0x070 TINY + +### + +HELLO: hello.bas + $(TOKENIZE) < hello.bas > HELLO + + +### + +BALL: ball.o + ld65 -o BALL ball.o -C $(LINKER_SCRIPTS)/apple2_300.inc + +ball.o: ball.s + ca65 -o ball.o ball.s -l ball.lst + +### + +PATTERN: pattern.o + ld65 -o PATTERN pattern.o -C $(LINKER_SCRIPTS)/apple2_3f5.inc + +pattern.o: pattern.s + ca65 -o pattern.o pattern.s -l pattern.lst + +### + +TINY: tiny.o + ld65 -o TINY tiny.o -C $(LINKER_SCRIPTS)/apple2_70_zp.inc + +tiny.o: tiny.s + ca65 -o tiny.o tiny.s -l tiny.lst + + +### + +clean: + rm -f *~ *.o *.lst HELLO BALL PATTERN TINY diff --git a/graphics/hgr/sprite/apple2_36b.inc b/graphics/hgr/amiga_ball/apple2_36b.inc similarity index 100% rename from graphics/hgr/sprite/apple2_36b.inc rename to graphics/hgr/amiga_ball/apple2_36b.inc diff --git a/graphics/hgr/sprite/apple2_70_zp.inc b/graphics/hgr/amiga_ball/apple2_70_zp.inc similarity index 100% rename from graphics/hgr/sprite/apple2_70_zp.inc rename to graphics/hgr/amiga_ball/apple2_70_zp.inc diff --git a/graphics/hgr/sprite/ball.s b/graphics/hgr/amiga_ball/ball.s similarity index 100% rename from graphics/hgr/sprite/ball.s rename to graphics/hgr/amiga_ball/ball.s diff --git a/graphics/hgr/amiga_ball/hello.bas b/graphics/hgr/amiga_ball/hello.bas new file mode 100644 index 00000000..133a44bb --- /dev/null +++ b/graphics/hgr/amiga_ball/hello.bas @@ -0,0 +1,2 @@ +5 HOME +10 PRINT CHR$(4);"CATALOG" diff --git a/graphics/hgr/sprite/pattern.s b/graphics/hgr/amiga_ball/pattern.s similarity index 100% rename from graphics/hgr/sprite/pattern.s rename to graphics/hgr/amiga_ball/pattern.s diff --git a/graphics/hgr/sprite/tiny_30.s b/graphics/hgr/amiga_ball/tiny_30.s similarity index 100% rename from graphics/hgr/sprite/tiny_30.s rename to graphics/hgr/amiga_ball/tiny_30.s diff --git a/graphics/hgr/sprite/Makefile b/graphics/hgr/sprite/Makefile index 75e2f8a3..ff6b457a 100644 --- a/graphics/hgr/sprite/Makefile +++ b/graphics/hgr/sprite/Makefile @@ -1,51 +1,32 @@ include ../../../Makefile.inc DOS33 = ../../../utils/dos33fs-utils/dos33 +DOS33_RAW = ../../../utils/dos33fs-utils/dos33_raw TOKENIZE = ../../../utils/asoft_basic-utils/tokenize_asoft LINKER_SCRIPTS = ../../../linker_scripts -EMPTY_DISK = ../../../empty_disk/empty.dsk +EMPTY_DISK = ../../../empty_disk all: sprite.dsk -sprite.dsk: HELLO BALL PATTERN TINY - cp $(EMPTY_DISK) sprite.dsk +sprite.dsk: HELLO SPRITE + cp $(EMPTY_DISK)/empty.dsk sprite.dsk $(DOS33) -y sprite.dsk SAVE A HELLO - $(DOS33) -y sprite.dsk BSAVE -a 0x0300 BALL - $(DOS33) -y sprite.dsk BSAVE -a 0x036B PATTERN - $(DOS33) -y sprite.dsk BSAVE -a 0x070 TINY - + $(DOS33) -y sprite.dsk BSAVE -a 0x6000 SPRITE ### HELLO: hello.bas $(TOKENIZE) < hello.bas > HELLO - ### -BALL: ball.o - ld65 -o BALL ball.o -C $(LINKER_SCRIPTS)/apple2_300.inc - -ball.o: ball.s - ca65 -o ball.o ball.s -l ball.lst - -### - -PATTERN: pattern.o - ld65 -o PATTERN pattern.o -C $(LINKER_SCRIPTS)/apple2_3f5.inc - -pattern.o: pattern.s - ca65 -o pattern.o pattern.s -l pattern.lst - -### - -TINY: tiny.o - ld65 -o TINY tiny.o -C $(LINKER_SCRIPTS)/apple2_70_zp.inc - -tiny.o: tiny.s - ca65 -o tiny.o tiny.s -l tiny.lst +SPRITE: sprite.o + ld65 -o SPRITE sprite.o -C $(LINKER_SCRIPTS)/apple2_6000.inc +sprite.o: sprite.s graphics/graphics.inc + ca65 -o sprite.o sprite.s -l sprite.lst ### clean: - rm -f *~ *.o *.lst HELLO BALL PATTERN TINY + rm -f *~ *.o *.lst HELLO SPRITE + diff --git a/graphics/hgr/sprite/decompress_fast_v2.s b/graphics/hgr/sprite/decompress_fast_v2.s new file mode 100644 index 00000000..fb2f24ad --- /dev/null +++ b/graphics/hgr/sprite/decompress_fast_v2.s @@ -0,0 +1,370 @@ +; note -- modified by Vince Weaver to assemble with ca65 +; in this case, A = page to decompress to +; getsrc_smc+1, getsrc_smc+2 is src location + +; ----------------------------------------------------------------------------- +; Decompress raw LZSA2 block. +; Create one with lzsa -r -f2 +; +; in: +; * LZSA_SRC_LO and LZSA_SRC_HI contain the compressed raw block address +; * LZSA_DST_LO and LZSA_DST_HI contain the destination buffer address +; +; out: +; * LZSA_DST_LO and LZSA_DST_HI contain the last decompressed byte address, +1 +; +; ----------------------------------------------------------------------------- +; Backward decompression is also supported, use lzsa -r -b -f2 +; To use it, also define BACKWARD_DECOMPRESS=1 before including this code! +; +; in: +; * LZSA_SRC_LO/LZSA_SRC_HI must contain the address of the last byte of compressed data +; * LZSA_DST_LO/LZSA_DST_HI must contain the address of the last byte of the destination buffer +; +; out: +; * LZSA_DST_LO/LZSA_DST_HI contain the last decompressed byte address, -1 +; +; ----------------------------------------------------------------------------- +; +; Copyright (C) 2019 Emmanuel Marty, Peter Ferrie +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source distribution. +; ----------------------------------------------------------------------------- + +;NIBCOUNT = $FC ; zero-page location for temp offset + +decompress_lzsa2_fast: + + sta LZSA_DST_HI + + ldy #$00 + sty LZSA_DST_LO + sty NIBCOUNT + +decode_token: + jsr getsrc ; read token byte: XYZ|LL|MMM + pha ; preserve token on stack + + and #$18 ; isolate literals count (LL) + beq no_literals ; skip if no literals to copy + cmp #$18 ; LITERALS_RUN_LEN_V2? + bcc prepare_copy_literals ; if less, count is directly embedded in token + + jsr getnibble ; get extra literals length nibble + ; add nibble to len from token + adc #$02 ; (LITERALS_RUN_LEN_V2) minus carry + cmp #$12 ; LITERALS_RUN_LEN_V2 + 15 ? + bcc prepare_copy_literals_direct ; if less, literals count is complete + + jsr getsrc ; get extra byte of variable literals count + ; the carry is always set by the CMP above + ; GETSRC doesn't change it + sbc #$EE ; overflow? + jmp prepare_copy_literals_direct + +prepare_copy_literals_large: + ; handle 16 bits literals count + ; literals count = directly these 16 bits + jsr getlargesrc ; grab low 8 bits in X, high 8 bits in A + tay ; put high 8 bits in Y + bcs prepare_copy_literals_high ; (*same as JMP PREPARE_COPY_LITERALS_HIGH but shorter) + +prepare_copy_literals: + lsr ; shift literals count into place + lsr + lsr + +prepare_copy_literals_direct: + tax + bcs prepare_copy_literals_large ; if so, literals count is large + +prepare_copy_literals_high: + txa + beq copy_literals + iny + +copy_literals: + jsr getput ; copy one byte of literals + dex + bne copy_literals + dey + bne copy_literals + +no_literals: + pla ; retrieve token from stack + pha ; preserve token again + asl + bcs repmatch_or_large_offset ; 1YZ: rep-match or 13/16 bit offset + + asl ; 0YZ: 5 or 9 bit offset + bcs offset_9_bit + + ; 00Z: 5 bit offset + + ldx #$FF ; set offset bits 15-8 to 1 + + jsr getcombinedbits ; rotate Z bit into bit 0, read nibble for bits 4-1 + ora #$E0 ; set bits 7-5 to 1 + bne got_offset_lo ; go store low byte of match offset and prepare match + +offset_9_bit: ; 01Z: 9 bit offset + ;;asl ; shift Z (offset bit 8) in place + rol + rol + and #$01 + eor #$FF ; set offset bits 15-9 to 1 + bne got_offset_hi ; go store high byte, read low byte of match offset and prepare match + ; (*same as JMP GOT_OFFSET_HI but shorter) + +repmatch_or_large_offset: + asl ; 13 bit offset? + bcs repmatch_or_16bit ; handle rep-match or 16-bit offset if not + + ; 10Z: 13 bit offset + + jsr getcombinedbits ; rotate Z bit into bit 8, read nibble for bits 12-9 + adc #$DE ; set bits 15-13 to 1 and substract 2 (to substract 512) + bne got_offset_hi ; go store high byte, read low byte of match offset and prepare match + ; (*same as JMP GOT_OFFSET_HI but shorter) + +repmatch_or_16bit: ; rep-match or 16 bit offset + ;;ASL ; XYZ=111? + bmi rep_match ; reuse previous offset if so (rep-match) + + ; 110: handle 16 bit offset + jsr getsrc ; grab high 8 bits +got_offset_hi: + tax + jsr getsrc ; grab low 8 bits +got_offset_lo: + sta OFFSLO ; store low byte of match offset + stx OFFSHI ; store high byte of match offset + +rep_match: +.ifdef BACKWARD_DECOMPRESS + + ; Backward decompression - substract match offset + + sec ; add dest + match offset + lda putdst+1 ; low 8 bits +OFFSLO = *+1 + sbc #$AA + sta copy_match_loop+1 ; store back reference address + lda putdst+2 +OFFSHI = *+1 + sbc #$AA ; high 8 bits + sta copy_match_loop+2 ; store high 8 bits of address + sec + +.else + + ; Forward decompression - add match offset + + clc ; add dest + match offset + lda putdst+1 ; low 8 bits +OFFSLO = *+1 + adc #$AA + sta copy_match_loop+1 ; store back reference address +OFFSHI = *+1 + lda #$AA ; high 8 bits + adc putdst+2 + sta copy_match_loop+2 ; store high 8 bits of address +.endif + + pla ; retrieve token from stack again + and #$07 ; isolate match len (MMM) + adc #$01 ; add MIN_MATCH_SIZE_V2 and carry + cmp #$09 ; MIN_MATCH_SIZE_V2 + MATCH_RUN_LEN_V2? + bcc prepare_copy_match ; if less, length is directly embedded in token + + jsr getnibble ; get extra match length nibble + ; add nibble to len from token + adc #$08 ; (MIN_MATCH_SIZE_V2 + MATCH_RUN_LEN_V2) minus carry + cmp #$18 ; MIN_MATCH_SIZE_V2 + MATCH_RUN_LEN_V2 + 15? + bcc prepare_copy_match ; if less, match length is complete + + jsr getsrc ; get extra byte of variable match length + ; the carry is always set by the CMP above + ; GETSRC doesn't change it + sbc #$E8 ; overflow? + +prepare_copy_match: + tax + bcc prepare_copy_match_y ; if not, the match length is complete + beq decompression_done ; if EOD code, bail + + ; Handle 16 bits match length + jsr getlargesrc ; grab low 8 bits in X, high 8 bits in A + tay ; put high 8 bits in Y + +prepare_copy_match_y: + txa + beq copy_match_loop + iny + +copy_match_loop: + lda $AAAA ; get one byte of backreference + jsr putdst ; copy to destination + +.ifdef BACKWARD_DECOMPRESS + + ; Backward decompression -- put backreference bytes backward + + lda copy_match_loop+1 + beq getmatch_adj_hi +getmatch_done: + dec copy_match_loop+1 + +.else + + ; Forward decompression -- put backreference bytes forward + + inc copy_match_loop+1 + beq getmatch_adj_hi +getmatch_done: + +.endif + + dex + bne copy_match_loop + dey + bne copy_match_loop + jmp decode_token + +.ifdef BACKWARD_DECOMPRESS + +getmatch_adj_hi: + dec copy_match_loop+2 + jmp getmatch_done + +.else + +getmatch_adj_hi: + inc copy_match_loop+2 + jmp getmatch_done +.endif + +getcombinedbits: + eor #$80 + asl + php + + jsr getnibble ; get nibble into bits 0-3 (for offset bits 1-4) + plp ; merge Z bit as the carry bit (for offset bit 0) +combinedbitz: + rol ; nibble -> bits 1-4; carry(!Z bit) -> bit 0 ; carry cleared +decompression_done: + rts + +getnibble: +NIBBLES = *+1 + lda #$AA + lsr NIBCOUNT + bcc need_nibbles + and #$0F ; isolate low 4 bits of nibble + rts + +need_nibbles: + inc NIBCOUNT + jsr getsrc ; get 2 nibbles + sta NIBBLES + lsr + lsr + lsr + lsr + sec + rts + +.ifdef BACKWARD_DECOMPRESS + + ; Backward decompression -- get and put bytes backward + +getput: + jsr getsrc +putdst: +LZSA_DST_LO = *+1 +LZSA_DST_HI = *+2 + sta $AAAA + lda putdst+1 + beq putdst_adj_hi + dec putdst+1 + rts + +putdst_adj_hi: + dec putdst+2 + dec putdst+1 + rts + +getlargesrc: + jsr getsrc ; grab low 8 bits + tax ; move to X + ; fall through grab high 8 bits + +getsrc: +LZSA_SRC_LO = *+1 +LZSA_SRC_HI = *+2 + lda $AAAA + pha + lda getsrc+1 + beq getsrc_adj_hi + dec getsrc+1 + pla + rts + +getsrc_adj_hi: + dec getsrc+2 + dec getsrc+1 + pla + rts + +.else + + ; Forward decompression -- get and put bytes forward + +getput: + jsr getsrc +putdst: +LZSA_DST_LO = *+1 +LZSA_DST_HI = *+2 + sta $AAAA + inc putdst+1 + beq putdst_adj_hi + rts + +putdst_adj_hi: + inc putdst+2 + rts + +getlargesrc: + jsr getsrc ; grab low 8 bits + tax ; move to X + ; fall through grab high 8 bits + +getsrc: +getsrc_smc: +LZSA_SRC_LO = *+1 +LZSA_SRC_HI = *+2 + lda $AAAA + inc getsrc+1 + beq getsrc_adj_hi + rts + +getsrc_adj_hi: + inc getsrc+2 + rts +.endif + diff --git a/graphics/hgr/sprite/graphics/Makefile b/graphics/hgr/sprite/graphics/Makefile new file mode 100644 index 00000000..f9bcdc8b --- /dev/null +++ b/graphics/hgr/sprite/graphics/Makefile @@ -0,0 +1,29 @@ + +PNG2RLE = ../../../../utils/gr-utils/png2rle +PNG2GR = ../../../../utils/gr-utils/png2gr +PNG2HGR = ../../../../utils/hgr-utils/png2hgr +LZSA = ~/research/lzsa/lzsa/lzsa +B2D = ../../../../utils/bmp2dhr/b2d + +all: graphics.inc + + +graphics.inc: \ + mona.lzsa + echo "mona_lzsa: .incbin \"mona.lzsa\"" > graphics.inc + + +### + +mona.lzsa: mona.hgr + $(LZSA) -r -f2 mona.hgr mona.lzsa + +mona.hgr: mona.png + $(PNG2HGR) mona.png > mona.hgr + +### + + +clean: + rm -f *~ outline.inc *.lzsa *.gr *.hgr + diff --git a/graphics/hgr/sprite/graphics/README b/graphics/hgr/sprite/graphics/README new file mode 100644 index 00000000..ffdb20db --- /dev/null +++ b/graphics/hgr/sprite/graphics/README @@ -0,0 +1 @@ +mona.png: by JiskeyJasket on twitter diff --git a/graphics/hgr/sprite/graphics/graphics.inc b/graphics/hgr/sprite/graphics/graphics.inc new file mode 100644 index 00000000..0d3d7ef0 --- /dev/null +++ b/graphics/hgr/sprite/graphics/graphics.inc @@ -0,0 +1 @@ +mona_lzsa: .incbin "mona.lzsa" diff --git a/graphics/hgr/sprite/graphics/mona.png b/graphics/hgr/sprite/graphics/mona.png new file mode 100644 index 0000000000000000000000000000000000000000..2286c2c79864cee62f012e421b544c14b6eefad9 GIT binary patch literal 18683 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 Ml2ey$khTo_Ut(mona_lzsa) + sta getsrc_smc+2 + + lda #$20 + + jsr decompress_lzsa2_fast + + + + ;================== + ; sprite stuff + + lda #10 + sta XX + lda #10 + sta YY + +forever: + jsr save_bg ; save bg + + jsr draw_sprite ; draw sprite + +keyloop: + lda KEYPRESS + bpl keyloop + + pha + jsr restore_bg ; restore bg + pla + +check_right: + cmp #'D'|$80 + bne check_left + + inc XX + jmp done_key + +check_left: + cmp #'A'|$80 + bne check_up + + dec XX + jmp done_key + +check_up: + cmp #'W'|$80 + bne check_down + + dec YY + dec YY + dec YY + dec YY + dec YY + + jmp done_key + +check_down: + cmp #'S'|$80 + bne done_key + + inc YY + inc YY + inc YY + inc YY + inc YY + + jmp done_key + +done_key: + lda KEYRESET +nokey: + + jmp forever + + + ;====================== + ; draw sprite + ;====================== + +draw_sprite: + + ldx #0 +sprite_yloop: + txa + pha + + clc + adc YY + + ldx #0 + ldy #0 + + ; calc GBASL/GBASH + jsr HPOSN ; (Y,X),(A) (values stored in HGRX,XH,Y) + + pla + tax + + ldy XX + + lda (GBASL),Y + and hand_mask_l,X + ora hand_sprite_l,X + sta (GBASL),Y + + iny + + lda (GBASL),Y + and hand_mask_r,X + ora hand_sprite_r,X + sta (GBASL),Y + + inx + cpx #14 + bne sprite_yloop + + rts + + + + ;====================== + ; save bg + ;====================== + +save_bg: + + ldx #0 +save_yloop: + txa + pha + + clc + adc YY + + ldx #0 + ldy #0 + + ; calc GBASL/GBASH + jsr HPOSN ; (Y,X),(A) (values stored in HGRX,XH,Y) + + pla + tax + + ldy XX + + lda (GBASL),Y + sta save_left,X + + iny + + lda (GBASL),Y + sta save_right,X + + inx + cpx #14 + bne save_yloop + + rts + + ;====================== + ; restore bg + ;====================== + +restore_bg: + + ldx #0 +restore_yloop: + txa + pha + + clc + adc YY + + ldx #0 + ldy #0 + + ; calc GBASL/GBASH + jsr HPOSN ; (Y,X),(A) (values stored in HGRX,XH,Y) + + pla + tax + + ldy XX + + lda save_left,X + sta (GBASL),Y + + iny + + lda save_right,X + sta (GBASL),Y + + + inx + cpx #14 + bne restore_yloop + + rts + + + +.include "decompress_fast_v2.s" + +.include "graphics/graphics.inc" + + +; hand sprite + +hand_mask_l: ; X 654 3 210 +.byte $9f ; 1 001 1 111 +.byte $8f ; 1 000 1 111 +.byte $8f ; 1 000 1 111 +.byte $8f ; 1 000 1 111 +.byte $88 ; 1 000 1 000 +.byte $80 ; 1 000 0 000 +.byte $80 ; 1 000 0 000 +.byte $80 ; 1 000 0 000 +.byte $81 ; 1 000 0 001 +.byte $81 ; 1 000 0 001 +.byte $83 ; 1 000 0 011 +.byte $87 ; 1 000 0 111 +.byte $8f ; 1 000 1 111 +.byte $8f ; 1 000 1 111 + +hand_sprite_l: ; X 654 3 210 +.byte $00 ; 0 000 0 000 +.byte $60 ; 0 110 0 000 +.byte $60 ; 0 110 0 000 +.byte $60 ; 0 110 0 000 +.byte $60 ; 0 110 0 000 +.byte $63 ; 0 110 0 011 +.byte $66 ; 0 110 0 110 +.byte $2c ; 0 010 1 100 +.byte $6c ; 0 110 1 100 +.byte $78 ; 0 111 1 000 +.byte $70 ; 0 111 0 000 +.byte $70 ; 0 111 0 000 +.byte $60 ; 0 110 0 000 +.byte $60 ; 0 110 0 000 + +hand_mask_r: ; X 654 3 210 +.byte $ff ; 1 111 1 111 +.byte $fe ; 1 111 1 110 +.byte $fe ; 1 111 1 110 +.byte $fe ; 1 111 1 110 +.byte $e0 ; 1 110 0 000 +.byte $80 ; 1 000 0 000 +.byte $80 ; 1 000 0 000 +.byte $80 ; 1 000 0 000 +.byte $80 ; 1 000 0 000 +.byte $80 ; 1 000 0 000 +.byte $80 ; 1 000 0 000 +.byte $80 ; 1 000 0 000 +.byte $c0 ; 1 100 0 000 +.byte $c0 ; 1 100 0 000 + +hand_sprite_r: ; X 654 3 210 +.byte $00 ; 0 000 0 000 +.byte $00 ; 0 000 0 000 +.byte $00 ; 0 000 0 000 +.byte $00 ; 0 000 0 000 +.byte $00 ; 0 000 0 000 +.byte $0A ; 0 000 1 010 +.byte $2A ; 0 010 1 010 +.byte $2D ; 0 010 1 101 +.byte $37 ; 0 011 0 111 +.byte $3F ; 0 011 1 111 +.byte $3F ; 0 011 1 111 +.byte $1F ; 0 001 1 111 +.byte $1F ; 0 001 1 111 +.byte $1F ; 0 001 1 111 + + +save_right: +.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + +save_left: +.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00