From 6f534c297a7341ab28d655b4d59d2414937d6d2a Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Mon, 2 Jan 2023 02:22:26 -0500 Subject: [PATCH] zero_wing: more nonsense --- demos/demosplash2022/Makefile | 23 +- demos/demosplash2022/file_id.diz | 12 + graphics/hgr/budge3d/Makefile | 31 + graphics/hgr/budge3d/hello.bas | 2 + graphics/hgr/budge3d/ship_cube.s | 1895 +++++++++++++++++++++++++ music/zero_wing/Makefile | 33 + music/zero_wing/gr_offsets.s | 5 + music/zero_wing/graphics/Makefile | 37 + music/zero_wing/graphics/captain.png | Bin 0 -> 2432 bytes music/zero_wing/graphics/cats.png | Bin 0 -> 3243 bytes music/zero_wing/graphics/operator.png | Bin 0 -> 3806 bytes music/zero_wing/hardware.inc | 87 ++ music/zero_wing/hello.bas | 2 + music/zero_wing/text_print.s | 63 + music/zero_wing/wait_keypress.s | 5 + music/zero_wing/zp.inc | 190 +++ music/zero_wing/zw.s | 131 ++ music/zero_wing/zx02_optim.s | 159 +++ 18 files changed, 2664 insertions(+), 11 deletions(-) create mode 100644 demos/demosplash2022/file_id.diz create mode 100644 graphics/hgr/budge3d/Makefile create mode 100644 graphics/hgr/budge3d/hello.bas create mode 100644 graphics/hgr/budge3d/ship_cube.s create mode 100644 music/zero_wing/Makefile create mode 100644 music/zero_wing/gr_offsets.s create mode 100644 music/zero_wing/graphics/Makefile create mode 100644 music/zero_wing/graphics/captain.png create mode 100644 music/zero_wing/graphics/cats.png create mode 100644 music/zero_wing/graphics/operator.png create mode 100644 music/zero_wing/hardware.inc create mode 100644 music/zero_wing/hello.bas create mode 100644 music/zero_wing/text_print.s create mode 100644 music/zero_wing/wait_keypress.s create mode 100644 music/zero_wing/zp.inc create mode 100644 music/zero_wing/zw.s create mode 100644 music/zero_wing/zx02_optim.s diff --git a/demos/demosplash2022/Makefile b/demos/demosplash2022/Makefile index d740b9ae..ce990c28 100644 --- a/demos/demosplash2022/Makefile +++ b/demos/demosplash2022/Makefile @@ -21,18 +21,19 @@ HELLO: hello.bas $(TOKENIZE) < hello.bas > HELLO -#submit: apple_desire512.zip +submit: apple2_desire.zip -#apple_desire512.zip: APPLE_DESIRE apple_desire.s file_id.diz apple_desire_512.dsk -# mkdir -p lovebyte2021_apple_desire_512 -# cp APPLE_DESIRE ./lovebyte2021_apple_desire_512 -# cp *.s ./lovebyte2021_apple_desire_512 -# cp file_id.diz ./lovebyte2021_apple_desire_512 -# cp apple_desire_512.dsk ./lovebyte2021_apple_desire_512 -# cp apple_desire_512.woz ./lovebyte2021_apple_desire_512 -# cp apple_desire_720p.mp4 ./lovebyte2021_apple_desire_512 -# cp desire2.png ./lovebyte2021_apple_desire_512 -# zip -r apple_desire512.zip lovebyte2021_apple_desire_512 +apple2_desire.zip: APPLE_DESIRE apple_desire.dsk + mkdir -p demosplash2022_apple2_desire + mkdir -p demosplash2022_apple2_desire/src + cp APPLE_DESIRE ./demosplash2022_apple2_desire + cp *.s ./demosplash2022_apple2_desire/src + cp *.inc ./demosplash2022_apple2_desire/src + cp file_id.diz ./demosplash2022_apple2_desire + cp apple_desire.dsk ./demosplash2022_apple2_desire + cp apple2_desire.mkv ./demosplash2022_apple2_desire + cp a2_desire_screen.png ./demosplash2022_apple2_desire + zip -r apple2_desire.zip demosplash2022_apple2_desire #### diff --git a/demos/demosplash2022/file_id.diz b/demos/demosplash2022/file_id.diz new file mode 100644 index 00000000..4aacecdc --- /dev/null +++ b/demos/demosplash2022/file_id.diz @@ -0,0 +1,12 @@ +Apple2 Desire +- +1k Apple II demo for Demosplash 2022 + +it's actually hard to fit a Mockingboard track this small +also messing around with shape tables as per usual + +by Deater / dSr +music by mA2E + +Note: assumes Mockingboard in Slot#4. +Music only plays on left speaker. diff --git a/graphics/hgr/budge3d/Makefile b/graphics/hgr/budge3d/Makefile new file mode 100644 index 00000000..13a6ea8e --- /dev/null +++ b/graphics/hgr/budge3d/Makefile @@ -0,0 +1,31 @@ +include ../../../Makefile.inc + +DOS33 = ../../../utils/dos33fs-utils/dos33 +TOKENIZE = ../../../utils/asoft_basic-utils/tokenize_asoft +LINKER_SCRIPTS = ../../../linker_scripts +EMPTY_DISK = ../../../empty_disk + +all: budge3d.dsk + +budge3d.dsk: HELLO SHIP_CUBE + cp $(EMPTY_DISK)/empty.dsk budge3d.dsk + $(DOS33) -y budge3d.dsk SAVE A HELLO + $(DOS33) -y budge3d.dsk BSAVE -a 0x300 SHIP_CUBE + + +### + +HELLO: hello.bas + $(TOKENIZE) < hello.bas > HELLO + +#### + +SHIP_CUBE: ship_cube.o + ld65 -o SHIP_CUBE ship_cube.o -C $(LINKER_SCRIPTS)/apple2_300.inc + +ship_cube.o: ship_cube.s + ca65 -o ship_cube.o ship_cube.s -l ship_cube.lst + +#### +clean: + rm -f *~ *.o *.lst HELLO SHIP_CUBE diff --git a/graphics/hgr/budge3d/hello.bas b/graphics/hgr/budge3d/hello.bas new file mode 100644 index 00000000..133a44bb --- /dev/null +++ b/graphics/hgr/budge3d/hello.bas @@ -0,0 +1,2 @@ +5 HOME +10 PRINT CHR$(4);"CATALOG" diff --git a/graphics/hgr/budge3d/ship_cube.s b/graphics/hgr/budge3d/ship_cube.s new file mode 100644 index 00000000..972b3079 --- /dev/null +++ b/graphics/hgr/budge3d/ship_cube.s @@ -0,0 +1,1895 @@ +;============================================================================ +; Disassembly of a module generated by Bill Budge's 3-D Graphics System and +; Game Tool. +; +; The tool itself is copyright 1980 California Pacific Computer Co. Modules +; may be marketed and sold so long as they provide a credit notice. +; +; The HRCG (code and font) is credited to Christopher Espinosa. +;=========================================================================== +; Disassembly by Andy McFadden, using 6502bench SourceGen v1.6. +; Last updated 2020/03/11 +; +; The manual refers to "points" and "lines" rather than "vertices" and +; "edges". For consistency the same nomenclature is used here. +; +; Two shapes are defined: the space shuttle model from the manual, and a +; simple cube 11 units on a side. The module is configured for XOR drawing, +; Applesoft BASIC interface, and includes the hi-res character generator. +; +; This makes extensive use of self-modifying code. Labels that begin with an +; underscore indicate self-modification targets. +;=========================================================================== +; Code interacts with the module by setting values in arrays and calling known +; entry points. The basic setup for Applesoft BASIC is: +; +; 1 DIM CODE%(15), X%(15), Y%(15), SCALE%(15), XROT%(15), YROT%(15), +; ZROT%(15), SX%(15), SY%(15) +; 2 RESET% = 7932:CLR% = 7951:HIRES% = 7983:CRNCH% = 7737:TXTGEN% = 768 +; +; You can define up to 16 shapes. Their parameters are stored in the various +; arrays: +; +; CODE%(n): 0 (do nothing), 1 (transform & draw), 2 (erase previous, +; transform, draw new), 3 (erase). +; X%(n): X coordinate of center (0-255). +; Y%(n): Y coordinate of center (0-191). +; SCALE%(n): scale factor, 0-15. 15 is full size, 0 is 1/16th. +; XROT%(n): rotation about X axis, 0-27. 0 is no rotation, 27 is just shy +; of 360 degrees. +; YROT%(n): rotation about Y axis. +; ZROT%(n): rotation about Z axis. +; SX%(n): (output) X coordinate of last point drawn. +; SY%(n): (output) Y coordinate of last point drawn. +; +; The code entry points are: +; RESET%: initializes graphics module, clears the screen, switches display +; to primary hi-res page. +; CLR%: clears both hi-res screens and switches to primary hi-res page. +; HIRES%: turns on primary hi-res page. +; CRNCH%: primary animation function. +; +; The "CRUNCH" function: +; - erases objects whose CODE value is 2 or 3 +; - computes new transformations for objects whose CODE value is 1 or 2 +; - draws objects whose CODE value is 1 or 2 +; - flips the display to the other page +; +; When configured for Integer BASIC, some of the array management is simpler, +; and an additional "missile" facility is available. +; +; When configured for use with assembly language, the various arrays live at +; fixed offsets starting around $6000. +;============================================================================ + +OpDEY = $88 ; DEY opcode +OpINY = $c8 ; INY opcode +OpDEX = $ca ; DEX opcode +OpINX = $e8 ; INX opcode +OpNOP = $ea ; NOP opcode + +; zero page addresses + +MON_WNDLEFT = $20 ; left column of scroll window +MON_WNDWDTH = $21 ; width of scroll window +MON_WNDTOP = $22 ; top of scroll window +MON_WNDBTM = $23 ; bottom of scroll window +MON_CH = $24 ; cursor horizontal displacement +MON_CV = $25 ; cursor vertical displacement +MON_CSWL = $36 ; character output hook (lo) +MON_CSWH = $37 ; character output hook (hi) +BAS_ARYTAB = $6b ; pointer to start of Applesoft array space (2b) + +CODE_arr = $6008 ; CODE array (dummy address) +X_arr = $602f ; X array (dummy address) +Y_arr = $6056 ; Y array (dummy address) +SCALE_arr = $607d ; SCALE array (dummy address) +XROT_arr = $60a4 ; XROT array (dummy address) +YROT_arr = $60cb ; YROT array (dummy address) +ZROT_arr = $60f2 ; ZROT array (dummy address) +SX_arr = $6119 ; SX array (dummy address) +SY_arr = $6140 ; SY array (dummy address) + +; soft switches +TXTCLR = $c050 ; RW display graphics +MIXCLR = $c052 ; RW display full screen +TXTPAGE1 = $c054 ; RW display page 1 +TXTPAGE2 = $c055 ; RW display page 2 (or read/write aux mem) +HIRES = $c057 ; RW display hi-res graphics + +; org $0300 + +;******************************************************************************* +; TXTGEN -- initialization entry point for the Hi-Res Character Generator * +; (HRCG). * +; * +; Just sets up the character output vector and returns. * +;******************************************************************************* +TXTGEN: + ldy #>TextOut ; 2 + sty MON_CSWH ; 3 + ldy #Glyphs ; 2 + sta glyph_ptr+1 ; 3 + ldy #$00 ; 2 count = 0 +CharLoop: + lda (glyph_ptr),Y ; 5+ get byte of glyph data + pha ; 3 + sty ytmp ; 3 save counter + ldy #$00 ; 2 + cmp (hbasl),Y ; ;5+ does nothing + sta (hbasl),Y ; 6 write to hi-res + lda hbasl+1 ; 3 + eor #$60 ; 2 page flip + sta hbasl+1 ; 3 + pla ; 4 + cmp (hbasl),Y ; 5+ does nothing + sta (hbasl),Y ; 6 write to other hi-res + ldy ytmp ; 3 restore counter + lda hbasl+1 ; 3 advance hi-res address + clc ; 2 + adc #$04 ; 2 within a block of 8 lines, it's this simple + sta hbasl+1 ; 3 + iny ; 2 + cpy #$08 ; 2 drawn 8 bytes? + bne CharLoop ; 2+ no, keep going + inc MON_CH ; 5 advance htab + lda MON_CH ; 3 + cmp MON_WNDWDTH ; 3 reached right edge of window? + bcc L0388 ; 2+ no, exit +NewLine: + lda MON_WNDLEFT ; 3 move down a line and to left edge + sta MON_CH ; 3 + inc MON_CV ; 5 + lda MON_CV ; 3 + cmp MON_WNDBTM ; 3 hit bottom? + bcc L0388 ; 2+ nope + lda MON_WNDTOP ; 3 yes, wrap around to top + sta MON_CV ; 3 +L0388: + ldy ysave ; 3 restore original Y-reg + pla ; 4 + rts ; 6 + +TextOut: + pha ; 3 + cmp #$8d ; 2 carriage return? + beq L03AE ; 2+ yes, draw it unmodified + and #$7f ; 2 strip hi bit + cmp #$04 ; 2 is it one of our special characters? + bcc SetRangeSel ; 2+ yes, branch + cmp #$40 ; 2 numbers or symbols? + bcc L039E ; 2+ yes, don't modify it + eor CharRangeSel ; 4 modify character range +L039E: + pha ; 3 save char (high bit stripped) + +; If you disable this next bit of code and print values like '/' ($2F), '?' +; ($3F), 'O' ($4F), '_' ($5F), or 'o' ($6F) the characters are partially +; corrupted. The reason is not at all obvious until you look at the addresses +; used to store them: +; +; $2F = $578 +; $3F = $5F8 +; $4F = $678 +; $5F = $6F8 +; +; Those are "screen holes", some of which are used to store values for DOS and +; peripheral slots. See https://retrocomputing.stackexchange.com/a/2541/56 +; +; The characters that get trampled are duplicated in the first seven control +; characters, the first four of which are used as special HRCG codes anyway (see +; below). $07 uses a bell glyph, since $7F (DEL) isn't really printable. + + and #$0f ; 2 check if it ends in $0f + cmp #$0f ; 2 if it's $4F,5F,6F,7f ... + bne L03AD ; 2+ not, just draw it + pla ; 4 restore char + and #$70 ; 2 convert to $40,50,60,70 + lsr ; 2 + lsr ; 2 + lsr ; 2 convert to $4,5,6,7 + lsr ; 2 (the AND #$70 seems unnecessary) + pha ; 3 +L03AD: + pla ; 4 +L03AE: + jsr DrawChar ; 6 + pla ; 4 restore unmodified char + rts ; 6 + +; The HRCG recognizes 4 special characters: +; +; - Ctrl+@ - CHR$(0) - shift to upper case ($40-5F) +; - Ctrl+A - CHR$(1) - shift to lower case ($60-7F) +; - Ctrl+B - CHR$(2) - shift to graphics symbols ($00-1F) +; - Ctrl+C - CHR$(3) - shift to digits/punctuation ($20-$3F) +; +; It might seem odd to include digits & punctuation, but the original ][/][+ +; keyboards lacked keys for ASCII symbols like brackets and curly braces. This +; provided an easy way to generate such characters, especially in Integer BASIC +; which didn't have a CHR$() function. + +SetRangeSel: + asl ; 2 convert 0/1/2/3... + asl ; 2 + asl ; 2 + asl ; 2 + asl ; 2 ...to $00/$20/$40/$60 + sta CharRangeSel ; 4 save + pla ; 4 + rts ; 6 + +; +; Value to EOR with characters in the $40-5F range to get other ranges. +; +CharRangeSel: .byte $00 +; junk 18 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00 + +; +; This chunk overwrites various DOS and system vectors. +; + +; 3d0 +.byte $4c,$bf,$9d,$4c,$84,$9d,$4c,$fd +.byte $aa,$4c,$b5,$b7,$ad,$0f,$9d,$ac +.byte $0e,$9d,$60,$ad,$c2,$aa,$ac,$c1 +.byte $aa,$60,$4c,$51,$a8,$ea,$ea,$4c + +.byte $59,$fa,$bf,$9d,$38,$4c,$58,$ff +.byte $4c,$65,$ff,$4c,$65,$ff,$65,$ff + +; +; HRCG glyphs, 8 bytes per character (1x8x127). Note this tramples the screen +; holes, which is why every 16th character looks slightly mangled. +; +; If the HRCG is not configured in, the program loads at $07FD instead. +; + +Glyphs: + .byte $00,$00,$00,$7c,$2a,$28,$2c,$00,$00,$00,$08,$1c,$1c,$08,$1c,$3e,$80,$40,$20,$10,$08,$04,$02,$00,$3c,$42,$40,$30,$08,$00,$08,$00 + .byte $3c,$42,$42,$42,$42,$42,$3c,$00,$00,$00,$00,$00,$00,$00,$00,$ff,$00,$00,$38,$44,$44,$44,$38,$00,$08,$14,$22,$22,$22,$41,$7f,$08 + .byte $10,$08,$04,$7e,$04,$08,$10,$00,$08,$10,$20,$7e,$20,$10,$08,$00,$08,$08,$08,$49,$2a,$1c,$08,$00,$08,$1c,$2a,$49,$08,$08,$08,$00 + .byte $08,$49,$2a,$1c,$49,$2a,$1c,$08,$40,$60,$70,$78,$70,$60,$40,$00,$40,$40,$20,$20,$13,$14,$0c,$08,$1f,$00,$00,$7c,$2a,$28,$3e,$00 + .byte $36,$7f,$7f,$7f,$3e,$1c,$08,$00,$08,$1c,$3e,$7f,$3e,$1c,$08,$00,$08,$1c,$3e,$7f,$7f,$2a,$08,$00,$08,$1c,$1c,$2a,$7f,$7f,$2a,$08 + .byte $3e,$08,$08,$22,$36,$2a,$22,$00,$00,$22,$14,$08,$14,$22,$00,$00,$04,$0e,$04,$04,$00,$00,$00,$00,$00,$08,$00,$3e,$00,$08,$00,$00 + .byte $18,$24,$08,$14,$08,$12,$0c,$00,$10,$38,$04,$04,$38,$10,$00,$00,$08,$1c,$08,$1c,$3e,$1c,$3e,$7f,$08,$3e,$1c,$08,$1c,$1c,$3e,$7f + .byte $00,$2a,$3e,$1c,$1c,$1c,$3e,$7f,$00,$10,$3c,$3e,$18,$0c,$1e,$3f,$00,$08,$18,$3a,$7b,$3e,$1c,$7f,$04,$00,$08,$1c,$1c,$08,$1c,$3e + + .byte $00,$00,$00,$00,$00,$00,$00,$00,$10,$10,$10,$10,$00,$00,$10,$00,$24,$24,$24,$00,$00,$00,$00,$00,$24,$24,$7e,$24,$7e,$24,$24,$00 + .byte $10,$78,$14,$38,$50,$3c,$10,$00,$00,$46,$26,$10,$08,$64,$62,$00,$0c,$12,$12,$0c,$52,$22,$5c,$00,$20,$10,$08,$00,$00,$00,$00,$00 + .byte $20,$10,$08,$08,$08,$10,$20,$00,$04,$08,$10,$10,$10,$08,$04,$00,$10,$54,$38,$7c,$38,$54,$10,$00,$00,$10,$10,$7c,$10,$10,$00,$00 + .byte $00,$00,$00,$00,$00,$18,$18,$0c,$00,$00,$00,$7e,$00,$00,$00,$00,$00,$00,$00,$00,$00,$18,$18,$00,$2f,$40,$20,$10,$08,$04,$02,$00 + .byte $3c,$42,$62,$5a,$46,$42,$3c,$00,$10,$18,$14,$10,$10,$10,$7c,$00,$3c,$42,$40,$30,$0c,$02,$7e,$00,$3c,$42,$40,$38,$40,$42,$3c,$00 + .byte $20,$30,$28,$24,$7e,$20,$20,$00,$7e,$02,$1e,$20,$40,$22,$1c,$00,$38,$04,$02,$3e,$42,$42,$3c,$00,$7e,$42,$20,$10,$08,$08,$08,$00 + .byte $3c,$42,$42,$3c,$42,$42,$3c,$00,$3c,$42,$42,$7c,$40,$20,$1c,$00,$00,$00,$18,$18,$00,$18,$18,$00,$00,$00,$18,$18,$00,$18,$18,$0c + .byte $20,$10,$08,$04,$08,$10,$20,$00,$00,$00,$3e,$00,$3e,$00,$00,$00,$04,$08,$10,$20,$10,$08,$04,$00,$60,$42,$40,$30,$08,$00,$08,$00 + + .byte $38,$44,$52,$6a,$32,$04,$78,$00,$18,$24,$42,$7e,$42,$42,$42,$00,$3e,$44,$44,$3c,$44,$44,$3e,$00,$3c,$42,$02,$02,$02,$42,$3c,$00 + .byte $3e,$44,$44,$44,$44,$44,$3e,$00,$7e,$02,$02,$1e,$02,$02,$7e,$00,$7e,$02,$02,$1e,$02,$02,$02,$00,$3c,$42,$02,$72,$42,$42,$3c,$00 + .byte $42,$42,$42,$7e,$42,$42,$42,$00,$38,$10,$10,$10,$10,$10,$38,$00,$70,$20,$20,$20,$20,$22,$1c,$00,$42,$22,$12,$0e,$12,$22,$42,$00 + .byte $02,$02,$02,$02,$02,$02,$7e,$00,$42,$66,$5a,$5a,$42,$42,$42,$00,$42,$46,$4a,$52,$62,$42,$42,$00,$60,$42,$42,$42,$42,$42,$3c,$00 + .byte $3e,$42,$42,$3e,$02,$02,$02,$00,$3c,$42,$42,$42,$52,$22,$5c,$00,$3e,$42,$42,$3e,$12,$22,$42,$00,$3c,$42,$02,$3c,$40,$42,$3c,$00 + .byte $7c,$10,$10,$10,$10,$10,$10,$00,$42,$42,$42,$42,$42,$42,$3c,$00,$42,$42,$42,$24,$24,$18,$18,$00,$42,$42,$42,$5a,$5a,$66,$42,$00 + .byte $42,$42,$24,$18,$24,$42,$42,$00,$44,$44,$44,$38,$10,$10,$10,$00,$7e,$40,$20,$18,$04,$02,$7e,$00,$3c,$04,$04,$04,$04,$04,$3c,$00 + .byte $00,$02,$04,$08,$10,$20,$40,$00,$3c,$20,$20,$20,$20,$20,$3c,$00,$10,$28,$44,$00,$00,$00,$00,$00,$02,$00,$00,$00,$00,$00,$00,$ff + + .byte $08,$10,$20,$00,$00,$00,$00,$00,$00,$00,$1c,$20,$3c,$22,$5c,$00,$02,$02,$3a,$46,$42,$46,$3a,$00,$00,$00,$3c,$02,$02,$02,$3c,$00 + .byte $40,$40,$5c,$62,$42,$62,$5c,$00,$00,$00,$3c,$42,$7e,$02,$3c,$00,$30,$48,$08,$3e,$08,$08,$08,$00,$00,$00,$5c,$62,$62,$5c,$40,$3c + .byte $02,$02,$3a,$46,$42,$42,$42,$00,$10,$00,$18,$10,$10,$10,$38,$00,$20,$00,$30,$20,$20,$20,$22,$1c,$02,$02,$22,$12,$0a,$16,$22,$00 + .byte $18,$10,$10,$10,$10,$10,$38,$00,$00,$00,$2e,$54,$54,$54,$54,$00,$00,$00,$3e,$44,$44,$44,$44,$00,$00,$00,$38,$44,$44,$44,$38,$00 + .byte $00,$00,$3a,$46,$46,$3a,$02,$02,$00,$00,$5c,$62,$62,$5c,$40,$40,$00,$00,$3a,$46,$02,$02,$02,$00,$00,$00,$7c,$02,$3c,$40,$3e,$00 + .byte $08,$08,$3e,$08,$08,$48,$30,$00,$00,$00,$42,$42,$42,$62,$5c,$00,$00,$00,$42,$42,$42,$24,$18,$00,$00,$00,$44,$44,$54,$54,$6c,$00 + .byte $00,$00,$42,$24,$18,$24,$42,$00,$00,$00,$42,$42,$62,$5c,$40,$3c,$00,$00,$7e,$20,$18,$04,$7e,$00,$38,$04,$04,$06,$04,$04,$38,$00 + .byte $08,$08,$08,$08,$08,$08,$08,$08,$0e,$10,$10,$30,$10,$10,$0e,$00,$28,$14,$00,$00,$00,$00,$00,$00 + +.byte $00,$00,$00,$00,$00 ; .junk 5 ;unused + +;=========================================================== +; +; If configured without the HRCG, the module starts here. * +; +; Note that all tables are page-aligned for performance. * +; +;=========================================================== + +NumObjects: .byte 2 ; number of objects + .byte 35 ; number of points (unused) + .byte 41 ; number of lines (unused) +; +; The next five tables represent the data as it was entered into the shape +; editor. There are two shapes. The first (space shuttle) starts at offset 0, +; has 27 points, and 29 lines. The second (cube) starts immediately after the +; first, has 8 points, and 12 lines. +; + +; 3D mesh X coordinates (-60, -57, ...) +ShapeXCoords: + .byte $c4,$c7,$c7,$c7,$c7,$d6,$d6,$d6 + .byte $d6,$f1,$f1,$00,$00,$15,$15,$1e + .byte $1e,$1e,$1e,$24,$24,$24,$24,$09 + .byte $1b,$15,$1e,$fb,$05,$05,$fb,$fb + + .byte $05,$05,$fb,$ec,$fc,$0c,$18,$28 + .byte $30,$44,$50,$74,$7c,$05,$fb,$00 + .byte $c4,$ca,$ca,$ca,$ca,$d6,$d6,$d6 + .byte $d6,$f1,$f1,$00,$00,$15,$15,$1e + + .byte $1e,$1e,$1e,$24,$24,$24,$24,$09 + .byte $1b,$15,$1e,$d8,$e8,$f8,$08,$18 + .byte $28,$9c,$c4,$ec,$14,$3c,$64,$c9 + .byte $37,$b5,$4b,$22,$de,$de,$f2,$0e + + .byte $22,$22,$de,$de,$f2,$0e,$22,$28 + .byte $39,$46,$d8,$c7,$ba,$00,$00,$00 + .byte $4d,$4d,$3f,$3f,$b3,$b3,$c1,$c1 + .byte $f9,$07,$07,$f9,$11,$ef,$ef,$11 + + .byte $08,$f8,$0a,$f6,$19,$e7,$19,$e7 + .byte $00,$fa,$06,$00,$00,$fc,$04,$fc + .byte $04,$fa,$06,$f6,$0a,$fc,$04,$f4 + .byte $0c,$fa,$06,$fa,$06,$f6,$0a,$f6 + + .byte $0a,$f4,$0c,$f4,$0c,$d0,$30,$d0 + .byte $30,$d0,$30,$d0,$30,$d0,$30,$d0 + .byte $30,$d3,$06,$fc,$1a,$ba,$00,$da + .byte $03,$16,$1a,$b0,$00,$ba,$02,$10 + + .byte $34,$1a,$98,$19,$2b,$da,$03,$1b + .byte $ab,$3b,$a0,$a0,$ab,$a4,$01,$df + .byte $82,$d9,$0b,$f2,$0c,$d8,$06,$06 + .byte $2b,$7c,$10,$5b,$08,$3f,$19,$16 + + .byte $0f,$01,$9c,$19,$23,$0f,$01,$97 + .byte $f2,$18,$24,$00,$0c,$c0,$f8,$06 + .byte $ed,$2b,$7c,$42,$1a,$ac,$00,$ba + .byte $5c,$06,$f1,$1a,$03,$00,$da,$06 + +; 3D mesh Y coordinates (0, 3, ...) +ShapeYCoords: + .byte $00,$03,$03,$fd,$fd,$06,$09,$fa,$f7,$09,$f7,$0f,$f1,$24,$dc,$24,$dc,$09,$f7,$09,$f7,$06,$fa,$00,$00,$00,$00,$fb,$fb,$05,$05,$fb + .byte $fb,$05,$05,$d0,$e0,$bc,$b0,$c4,$d8,$d0,$e0,$e0,$d0,$0a,$0a,$22,$00,$05,$05,$fb,$fb,$06,$09,$fa,$f7,$09,$f7,$0f,$f1,$24,$dc,$24 + .byte $dc,$09,$f7,$09,$f7,$06,$fa,$00,$00,$00,$00,$20,$20,$20,$20,$20,$20,$e0,$e0,$e0,$e0,$e0,$e0,$10,$10,$fa,$fa,$f4,$f4,$0c,$20,$20 + .byte $0c,$f4,$f4,$0c,$20,$20,$0c,$00,$00,$00,$00,$00,$00,$28,$39,$46,$f9,$07,$07,$f9,$f9,$07,$07,$f9,$4d,$4d,$3f,$3f,$ef,$ef,$11,$11 + .byte $0e,$0e,$1b,$1b,$11,$11,$e7,$e7,$00,$06,$06,$fa,$0a,$0a,$0a,$0a,$0a,$06,$06,$06,$06,$fa,$fa,$06,$06,$06,$06,$fa,$fa,$04,$04,$fc + .byte $fc,$04,$04,$fc,$fc,$0c,$0c,$f4,$f4,$0c,$0c,$f4,$f4,$0c,$0c,$f4,$f4,$06,$00,$4f,$0c,$d0,$d2,$a3,$02,$00,$2c,$0d,$c5,$e4,$e9,$f4 + .byte $04,$06,$00,$a2,$0d,$c1,$00,$00,$00,$20,$4d,$0a,$a9,$ff,$85,$31,$a0,$00,$a5,$24,$c9,$27,$d0,$09,$20,$8e,$fd,$85,$31,$a9,$06,$85 + .byte $24,$b1,$12,$c5,$30,$d0,$13,$e6,$31,$a4,$31,$c0,$10,$b0,$0b,$be,$f0,$00,$e4,$24,$90,$04,$86,$24,$90,$d6,$20,$ed,$fd,$e6,$12,$d0 + +; 3D mesh Z coordinates (0, 3, ...) +ShapeZCoords: + .byte $00,$03,$fd,$03,$fd,$09,$fa,$09,$fa,$fa,$fa,$fa,$fa,$fa,$fa,$fa,$fa,$fa,$fa,$fa,$fa,$09,$09,$09,$09,$1b,$1b,$fb,$fb,$fb,$fb,$05 + .byte $05,$05,$05,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$05,$fb,$05,$fb,$09,$fa,$09,$fa,$fa,$fa,$fa,$fa,$fa,$fa,$fa + .byte $fa,$fa,$fa,$fa,$fa,$09,$09,$09,$09,$1e,$1e,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$e2,$e2,$e0,$e0,$e0,$e0,$fd,$de,$c9,$fd,$de,$c9,$fb,$db,$c6,$c9,$c6,$c6,$c9,$c9,$c6,$c6,$c9,$c6,$c6,$c9,$c9,$28,$28,$2a,$2a + .byte $16,$16,$03,$03,$20,$20,$1e,$1e,$5a,$1e,$1e,$1e,$24,$22,$22,$0c,$0c,$12,$12,$10,$10,$0c,$0c,$e8,$e8,$e2,$e2,$e8,$e8,$fa,$fa,$fa + .byte $fa,$e8,$e8,$e8,$e8,$f4,$f4,$f4,$f4,$ee,$ee,$ee,$ee,$00,$00,$00,$00,$89,$f6,$01,$e2,$10,$27,$e8,$03,$64,$00,$0a,$00,$01,$00,$2b + .byte $35,$25,$37,$00,$4c,$45,$08,$2b,$d7,$02,$58,$36,$01,$f5,$20,$89,$f6,$6c,$3b,$38,$08,$ed,$07,$02,$eb,$f8,$4c,$07,$03,$6c,$38,$ec + .byte $28,$db,$02,$a5,$00,$20,$8e,$0a,$20,$89,$f6,$29,$d7,$03,$e2,$00,$60,$00,$20,$8e,$fd,$20,$ce,$0a,$20,$d5,$0e,$20,$c9,$09,$20,$89 + +; 3D mesh line definition: start points (0, 0, 0, ...) +LineStartPoint: ; b00 + .byte $00,$00,$00,$00,$01,$02,$03,$04,$06,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f,$10,$11,$12,$13,$05,$07,$13,$14,$15,$17,$19,$1a,$1b,$1c,$1d + .byte $1e,$1f,$20,$21,$22,$1b,$1c,$1d,$1e,$26,$27,$28,$29,$2a,$2b,$2d,$2e,$30,$30,$30,$30,$31,$32,$33,$34,$36,$38,$39,$3a,$3b,$3c,$3d + .byte $3e,$3f,$40,$41,$42,$43,$35,$37,$43,$44,$45,$47,$49,$48,$4b,$4c,$4d,$4e,$4f,$50,$4b,$57,$59,$51,$5d,$63,$5d,$5e,$5f,$65,$5f,$60 + .byte $5b,$60,$61,$66,$67,$5c,$5d,$62,$63,$6a,$5e,$5f,$64,$65,$6d,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7a,$7b,$7c,$7d,$7e,$7f,$80 + .byte $81,$7e,$7f,$7e,$7f,$84,$85,$84,$85,$86,$87,$88,$88,$88,$8c,$8c,$8d,$8e,$89,$8a,$91,$92,$93,$94,$93,$94,$8b,$8b,$97,$98,$99,$97 + .byte $98,$99,$9a,$9d,$a1,$a9,$9f,$a3,$ab,$9e,$a2,$aa,$a0,$a4,$ac,$39,$a3,$38,$01,$0a,$a5,$03,$4d,$d6,$03,$4a,$37,$38,$25,$39,$11,$3c + .byte $00,$29,$71,$28,$71,$00,$20,$da,$0b,$4c,$45,$08,$20,$89,$f6,$e8,$11,$3c,$00,$32,$b0,$71,$e0,$71,$22,$00,$6c,$08,$00,$14,$cd,$fe + .byte $00,$20,$ce,$0a,$20,$89,$f6,$29,$3a,$28,$3b,$eb,$00,$20,$8e,$0a,$20,$89,$f6,$29,$38,$2a,$39,$f8,$28,$b9,$f8,$00,$20,$cc,$0b,$20 + +; 3D mesh line definition: end points (1, 2, 3, ...) +LineEndPoint: ; c00 + .byte $01,$02,$03,$04,$05,$06,$07,$08 + .byte $09,$0a,$0b,$0c,$0d,$0e,$0f,$10 + .byte $11,$12,$13,$14,$14,$15,$16,$15 + .byte $16,$16,$19,$1a,$18,$1c,$1d,$1e + + .byte $1b,$20,$21,$22,$1f,$1f,$20,$21 + .byte $22,$27,$28,$29,$2a,$2b,$2c,$2f + .byte $2f,$31,$32,$33,$34,$35,$36,$37 + .byte $38,$39,$3a,$3b,$3c,$3d,$3e,$3f + + .byte $40,$41,$42,$43,$44,$44,$45,$46 + .byte $45,$46,$46,$49,$4a,$4a,$51,$52 + .byte $53,$54,$55,$56,$50,$58,$5a,$56 + .byte $5e,$64,$63,$64,$60,$66,$65,$66 + + .byte $67,$67,$68,$68,$69,$6a,$6a,$6b + .byte $6b,$6c,$6d,$6d,$6e,$6e,$6f,$71 + .byte $72,$73,$70,$75,$76,$77,$74,$79 + .byte $7a,$7b,$78,$7d,$7e,$7f,$7c,$82 + + .byte $83,$81,$80,$85,$84,$80,$81,$60 + .byte $5d,$84,$85,$89,$8a,$8b,$8d,$8e + .byte $8f,$90,$91,$92,$93,$94,$95,$96 + .byte $97,$98,$9b,$9c,$99,$9a,$9a,$9b + + .byte $9c,$9b,$9c,$a5,$a9,$ad,$a7,$ab + .byte $af,$a6,$aa,$ae,$a8,$ac,$b0,$10 + .byte $dd,$08,$3f,$19,$6b,$0f,$00,$20 + .byte $d0,$09,$20,$0c,$fd,$c9,$d3,$66 + + .byte $33,$20,$ce,$0a,$a9,$ff,$85,$2f + .byte $d0,$00,$20,$61,$0c,$20,$89,$f6 + .byte $11,$00,$02,$29,$d4,$06,$04,$49 + .byte $51,$01,$f8,$4a,$06,$03,$51,$01 + + .byte $fa,$21,$3a,$f2,$42,$51,$d3,$07 + .byte $fb,$19,$00,$02,$11,$7c,$03,$24 + .byte $71,$2a,$71,$00,$20,$7b,$0d,$24 + .byte $33,$10,$0c,$20,$0c,$fd,$c9,$83 + +; +; For shape N, the index of the first point. +; +; Shape #0 uses points $00-1A, shape #1 uses points $1B-22. (Data at offsets 2- +; 15 is junk.) +FirstPointIndex: + .byte $00,$1b,$08,$0c,$0d,$1d,$2d,$30,$4b,$5b,$88,$7c,$03,$61,$39,$e9 + +; For shape N, the index of the last point + 1. +LastPointIndex: + .byte $1b,$23,$0c,$0d,$1d,$2d,$30,$4b,$5b,$88,$b1,$2a,$1a,$00,$02,$ba + +; +; For shape N, the index of the first line. +; +; Shape #0 uses lines $00-1C, shape #1 uses lines $1D-28. (Data at offsets 2-15 +; is junk.) + +FirstLineIndex: + .byte $00,$1d,$0c,$01,$12,$20,$2f,$31,$4e,$58,$8b,$01,$9c,$00,$a5,$16 + +; For shape N, the index of the last point + 1. +LastLineIndex: + .byte $1d,$29,$12,$01,$20,$2f,$31,$4e,$58,$8b,$af,$fe,$4c,$45,$08,$20 + +; +; Indexes into the rotation tables. One entry for each rotation value (0-27). +; The "low" and "high" tables have the same value at each position, just shifted +; over 4 bits. +; +; Mathematically, cosine has the same shape as sine, but is shifted by PI/2 (one +; quarter period) ahead of it. That's why there are two sets of tables, one of +; which is shifted by 7 bytes. +; +; See the comments above RotTabLo for more details. +; + +RotIndexLo_sin: + .byte $70,$60,$50,$40,$30,$20,$10,$00,$10,$20,$30,$40,$50,$60,$70,$80,$90,$a0,$b0,$c0,$d0,$e0,$d0,$c0,$b0,$a0,$90,$80 +RotIndexHi_sin: + .byte $07,$06,$05,$04,$03,$02,$01,$00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0d,$0c,$0b,$0a,$09,$08 +RotIndexLo_cos: + .byte $00,$10,$20,$30,$40,$50,$60,$70,$80,$90,$a0,$b0,$c0,$d0,$e0,$d0,$c0,$b0,$a0,$90,$80,$70,$60,$50,$40,$30,$20,$10 +RotIndexHi_cos: + .byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0d,$0c,$0b,$0a,$09,$08,$07,$06,$05,$04,$03,$02,$01 + +; +; Indexes into the scale tables. One entry for each scale value (0-15). See +; the comments above ScaleTabLo for more details. +; +ScaleIndexLo: + .byte $00,$10,$20,$30,$40,$50,$60,$70,$80,$90,$a0,$b0,$c0,$d0,$e0,$f0 + +ScaleIndexHi: + .byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f + +; +; Junk, pads to end of 256-byte page. +.align $0100 ; (48 bytes) + +; +; These four buffers hold transformed points in screen coordinates. The points +; are in the same order as they are in the mesh definition. +; +; One pair of tables holds the X/Y screen coordinates from the previous frame, +; the other pair of tables holds the coordinates being transformed for the +; current frame. We need two sets because we're display set 0 while generating +; set 1, and after we flip we need to use set 0 again to erase the display. +; +; ---------- +; +; Computed X coordinate, set 0. +XCoord0_0E: ; 0e00 + .byte $00 + .align $100 + +; Computed Y coordinate, set 0. +YCoord0_0F: ; 0f00 + .byte $00 + .align $100 + +; Computed X coordinate, set 1. +XCoord1_10: ; 1000 + .byte $00 + .align $100 + +; Computed Y coordinate, set 1. +YCoord1_11: ; 1100 + .byte $00 + .align $100 + +; +; Math constants for rotation. +; +; To compute X * cos(theta), start by converting theta (0-27) into a table base +; address (using the 28-byte tables RotIndexLo_cos / RotIndexHi_cos). Split the +; X coordinate into nibbles, use the low 4 bits to index into the adjusted +; RotTabLo pointer, and the high 4 bits to index into the adjusted RotTabHi +; pointer. Add the values at those locations together. +; +; This is similar to the way the scale table works. See ScaleTableLo, below, +; for a longer explanation of how the nibbles are used. +; +; As an example, suppose we have a point at (36,56), and we want to rotate it 90 +; degrees (rot=7). We use the RotIndex tables to get the table base addresses: +; sin=$00/$00 ($1200/$1300), cos=$70/$07 ($1270/$1307). We split the +; coordinates into nibbles without shifting ($24,$38 --> $20 $04, $30 $08), and +; use the nibbles as indexes into the tables: +; +; X * cos(theta) = ($1274)+($1327) = $00+$00 = 0 +; Y * sin(theta) = ($1208)+($1330) = $08+$30 = 56 +; X * sin(theta) = ($1204)+($1320) = $04+$20 = 36 +; Y * cos(theta) = ($1278)+($1337) = $00+$00 = 0 +; +; XC = X*cos(theta) - Y*sin(theta) = -56 +; YC = X*sin(theta) + Y*cos(theta) = 36 +; +; which is exactly what we expected (counter-clockwise). +; +; The largest value from the index table is $EE, so that last 17 bytes in each +; table are unused. +; + +RotTabLo: ; 1200 + .byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f,$00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f + .byte $00,$01,$02,$03,$04,$05,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$00,$01,$02,$02,$03,$04,$05,$05,$06,$07,$08,$09,$09,$0a,$0b,$0c + .byte $00,$01,$01,$02,$02,$03,$04,$04,$05,$06,$06,$07,$07,$08,$09,$09,$00,$00,$01,$01,$02,$02,$03,$03,$03,$04,$04,$05,$05,$06,$06,$07 + .byte $00,$00,$00,$01,$01,$01,$01,$02,$02,$02,$02,$02,$03,$03,$03,$03,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$ff,$ff,$ff,$ff,$fe,$fe,$fe,$fe,$fe,$fd,$fd,$fd,$fd,$00,$00,$ff,$ff,$fe,$fe,$fd,$fd,$fd,$fc,$fc,$fb,$fb,$fa,$fa,$f9 + .byte $00,$ff,$ff,$fe,$fe,$fd,$fc,$fc,$fb,$fa,$fa,$f9,$f9,$f8,$f7,$f7,$00,$ff,$fe,$fe,$fd,$fc,$fb,$fb,$fa,$f9,$f8,$f7,$f7,$f6,$f5,$f4 + .byte $00,$ff,$fe,$fd,$fc,$fb,$fb,$fa,$f9,$f8,$f7,$f6,$f5,$f4,$f3,$f2,$00,$ff,$fe,$fd,$fc,$fb,$fb,$fa,$f8,$f7,$f6,$f5,$f4,$f3,$f2,$f1 + .byte $00,$ff,$fe,$fd,$fc,$fb,$fa,$f9,$f8,$f7,$f6,$f5,$f4,$f3,$f2,$f1,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + +RotTabHi: ; 1300 + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$10,$10,$0e,$0d,$0a,$07,$04,$00,$fc,$f9,$f6,$f3,$f2,$f0,$f0,$00 + .byte $20,$1f,$1d,$19,$14,$0e,$07,$00,$f9,$f2,$ec,$e7,$e3,$e1,$e0,$00,$30,$2f,$2b,$26,$1e,$15,$0b,$00,$f5,$eb,$e2,$da,$d5,$d1,$d0,$00 + .byte $40,$3e,$3a,$32,$28,$1c,$0e,$00,$f2,$e4,$d8,$ce,$c6,$c2,$c0,$00,$50,$4e,$48,$3f,$32,$23,$12,$00,$ee,$dd,$ce,$c1,$b8,$b2,$b0,$00 + .byte $60,$5e,$56,$4b,$3c,$2a,$15,$00,$eb,$d6,$c4,$b5,$aa,$a2,$a0,$00,$70,$6d,$65,$58,$46,$31,$19,$00,$e7,$cf,$ba,$a8,$9b,$93,$90,$00 + .byte $80,$83,$8d,$9c,$b0,$c8,$e4,$00,$1c,$38,$50,$64,$73,$7d,$80,$00,$90,$93,$9b,$a8,$ba,$cf,$e7,$00,$19,$31,$46,$58,$65,$6d,$70,$00 + .byte $a0,$a2,$aa,$b5,$c4,$d6,$eb,$00,$15,$2a,$3c,$4b,$56,$5e,$60,$00,$b0,$b2,$b8,$c1,$ce,$dd,$ee,$00,$12,$23,$32,$3f,$48,$4e,$50,$00 + .byte $c0,$c2,$c6,$ce,$d8,$e4,$f2,$00,$0e,$1c,$28,$32,$3a,$3e,$40,$00,$d0,$d1,$d5,$da,$e2,$eb,$f5,$00,$0b,$15,$1e,$26,$2b,$2f,$30,$00 + .byte $e0,$e1,$e3,$e7,$ec,$f2,$f9,$00,$07,$0e,$14,$19,$1d,$1f,$20,$00,$f0,$f0,$f2,$f3,$f6,$f9,$fc,$00,$04,$07,$0a,$0d,$0e,$10,$10,$00 + +; +; Divide-by-7 table. Used to divide the X coordinate (0-255) by 7, yielding a +; byte offset for the hi-res screen column. +; +Div7Tab: ; 1400 + .byte $00,$00,$00,$00,$00,$00,$00,$01,$01,$01,$01,$01,$01,$01,$02,$02,$02,$02,$02,$02,$02,$03,$03,$03,$03,$03,$03,$03,$04,$04,$04,$04 + .byte $04,$04,$04,$05,$05,$05,$05,$05,$05,$05,$06,$06,$06,$06,$06,$06,$06,$07,$07,$07,$07,$07,$07,$07,$08,$08,$08,$08,$08,$08,$08,$09 + .byte $09,$09,$09,$09,$09,$09,$0a,$0a,$0a,$0a,$0a,$0a,$0a,$0b,$0b,$0b,$0b,$0b,$0b,$0b,$0c,$0c,$0c,$0c,$0c,$0c,$0c,$0d,$0d,$0d,$0d,$0d + .byte $0d,$0d,$0e,$0e,$0e,$0e,$0e,$0e,$0e,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$10,$10,$10,$10,$10,$10,$10,$11,$11,$11,$11,$11,$11,$11,$12,$12 + .byte $12,$12,$12,$12,$12,$13,$13,$13,$13,$13,$13,$13,$14,$14,$14,$14,$14,$14,$14,$15,$15,$15,$15,$15,$15,$15,$16,$16,$16,$16,$16,$16 + .byte $16,$17,$17,$17,$17,$17,$17,$17,$18,$18,$18,$18,$18,$18,$18,$19,$19,$19,$19,$19,$19,$19,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1b,$1b,$1b + .byte $1b,$1b,$1b,$1b,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1d,$1d,$1d,$1d,$1d,$1d,$1d,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1f,$1f,$1f,$1f,$1f,$1f,$1f + .byte $20,$20,$20,$20,$20,$20,$20,$21,$21,$21,$21,$21,$21,$21,$22,$22,$22,$22,$22,$22,$22,$23,$23,$23,$23,$23,$23,$23,$24,$24,$24,$24 + +; +; Hi-res bit table. Converts the X coordinate (0-255) into a bit position +; within a byte. (Essentially 2 to the power of the remainder of the coordinate +; divided by 7.) +; + +HiResBitTab: ; 1500 + .byte $01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08 + .byte $10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01 + .byte $02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10 + .byte $20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02 + .byte $04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20 + .byte $40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04 + .byte $08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40 + .byte $01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08 + +; +; Hi-res Y-coordinate lookup table, low byte. Values 0-191 are meaningful, 192- +; 255 are junk. +; + +YTableLo: ; 1600 + .byte $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80,$00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80 + .byte $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80,$00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80 + .byte $28,$28,$28,$28,$28,$28,$28,$28,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$28,$28,$28,$28,$28,$28,$28,$28,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$a8 + .byte $28,$28,$28,$28,$28,$28,$28,$28,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$28,$28,$28,$28,$28,$28,$28,$28,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$a8 + .byte $50,$50,$50,$50,$50,$50,$50,$50,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$50,$50,$50,$50,$50,$50,$50,$50,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$d0 + .byte $50,$50,$50,$50,$50,$50,$50,$50,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$50,$50,$50,$50,$50,$50,$50,$50,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$d0 +.align $0100 ; (64 bytes) + +;============================================== +; Hi-res Y-coordinate lookup table, high byte. +;============================================== + +YTableHi: + .byte $00,$04,$08,$0c,$10,$14,$18,$1c + .byte $00,$04,$08,$0c,$10,$14,$18,$1c + .byte $01,$05,$09,$0d,$11,$15,$19,$1d + .byte $01,$05,$09,$0d,$11,$15,$19,$1d + + .byte $02,$06,$0a,$0e,$12,$16,$1a,$1e + .byte $02,$06,$0a,$0e,$12,$16,$1a,$1e + .byte $03,$07,$0b,$0f,$13,$17,$1b,$1f + .byte $03,$07,$0b,$0f,$13,$17,$1b,$1f + + .byte $00,$04,$08,$0c,$10,$14,$18,$1c + .byte $00,$04,$08,$0c,$10,$14,$18,$1c + .byte $01,$05,$09,$0d,$11,$15,$19,$1d + .byte $01,$05,$09,$0d,$11,$15,$19,$1d + + .byte $02,$06,$0a,$0e,$12,$16,$1a,$1e + .byte $02,$06,$0a,$0e,$12,$16,$1a,$1e + .byte $03,$07,$0b,$0f,$13,$17,$1b,$1f + .byte $03,$07,$0b,$0f,$13,$17,$1b,$1f + + .byte $00,$04,$08,$0c,$10,$14,$18,$1c + .byte $00,$04,$08,$0c,$10,$14,$18,$1c + .byte $01,$05,$09,$0d,$11,$15,$19,$1d + .byte $01,$05,$09,$0d,$11,$15,$19,$1d + + .byte $02,$06,$0a,$0e,$12,$16,$1a,$1e + .byte $02,$06,$0a,$0e,$12,$16,$1a,$1e + .byte $03,$07,$0b,$0f,$13,$17,$1b,$1f + .byte $03,$07,$0b,$0f,$13,$17,$1b,$1f + +.align $0100 ; (64 bytes) + +; +; Math constants for scaling. +; +; Each table has 16 sets of 16 entries, with one set for each of the 16 possible +; scale values. The values within a set determine how one 4-bit nibble of the +; coordinate is scaled. +; +; Suppose you want to scale the value 100 ($64) by scale factor 8 (a bit over +; half size). We begin by using self-modifying code to select the table +; subsets. This is done in a clever way to avoid shifting. The instructions +; that load from ScaleTabLo are modified to reference $1800, $1810, $1820, and +; so on. The instructions that load from ScaleTabHi reference $1900, $1901, +; $1902, etc. The offset comes from the two 16-byte ScaleIndex tables. For a +; scale factor of 8, we'll be using $1880 and $1908 as the base addresses. +; +; To do the actual scaling, we mask to get the low part of the value ($04) and +; index into ScaleTabLo, at address $1884. We mask the high part of the value +; ($60) and index into ScaleTabHi, at $1968. We add the values there ($02, $36) +; to get $38 = 56, which is just over half size as expected. +; +; This is an approximation, but so is any integer division, and it's done in +; 512+32=544 bytes instead of the 16*256=4096 bytes that you'd need for a fully- +; formed scale. For hi-res graphics it's certainly good enough. +; +; 32 = $20 = ($1880)+($1928) = 18 (.563) +; 40 = $28 = ($1888)+($1928) = 22 (.55) +; 47 = $2F = ($188F)+($1928) = 26 (.553) +; 48 = $30 = ($1880)+($1938) = 27 (.563) +; 100 = $64 = ($1884)+($1968) = 56 (.56) +; + +ScaleTabLo: + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $01,$01,$01,$01,$01,$01,$01,$01 + + .byte $00,$00,$00,$00,$00,$00,$01,$01 + .byte $01,$01,$01,$02,$02,$02,$02,$02 + .byte $00,$00,$00,$00,$01,$01,$01,$01 + .byte $02,$02,$02,$02,$03,$03,$03,$03 + + .byte $00,$00,$00,$00,$01,$01,$01,$02 + .byte $02,$02,$03,$03,$03,$04,$04,$04 + .byte $00,$00,$00,$01,$01,$01,$02,$02 + .byte $03,$03,$03,$04,$04,$04,$05,$05 + + .byte $00,$00,$00,$01,$01,$02,$02,$03 + .byte $03,$03,$04,$04,$05,$05,$06,$06 + .byte $00,$00,$01,$01,$02,$02,$03,$03 + .byte $04,$04,$05,$05,$06,$06,$07,$07 + + .byte $00,$00,$01,$01,$02,$02,$03,$03 + .byte $04,$05,$05,$06,$06,$07,$07,$08 + .byte $00,$00,$01,$01,$02,$03,$03,$04 + .byte $05,$05,$06,$06,$07,$08,$08,$09 + + .byte $00,$00,$01,$02,$02,$03,$04,$04 + .byte $05,$06,$06,$07,$08,$08,$09,$0a + .byte $00,$00,$01,$02,$03,$03,$04,$05 + .byte $06,$06,$07,$08,$09,$09,$0a,$0b + + .byte $00,$00,$01,$02,$03,$04,$04,$05 + .byte $06,$07,$08,$08,$09,$0a,$0b,$0c + .byte $00,$00,$01,$02,$03,$04,$05,$06 + .byte $07,$07,$08,$09,$0a,$0b,$0c,$0d + + .byte $00,$00,$01,$02,$03,$04,$05,$06 + .byte $07,$08,$09,$0a,$0b,$0c,$0d,$0e + .byte $00,$01,$02,$03,$04,$05,$06,$07 + .byte $08,$09,$0a,$0b,$0c,$0d,$0e,$0f + +ScaleTabHi: + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $01,$02,$03,$04,$05,$06,$07,$08 + .byte $09,$0a,$0b,$0c,$0d,$0e,$0f,$10 + + .byte $02,$04,$06,$08,$0a,$0c,$0e,$10 + .byte $12,$14,$16,$18,$1a,$1c,$1e,$20 + .byte $03,$06,$09,$0c,$0f,$12,$15,$18 + .byte $1b,$1e,$21,$24,$27,$2a,$2d,$30 + + .byte $04,$08,$0c,$10,$14,$18,$1c,$20 + .byte $24,$28,$2c,$30,$34,$38,$3c,$40 + .byte $05,$0a,$0f,$14,$19,$1e,$23,$28 + .byte $2d,$32,$37,$3c,$41,$46,$4b,$50 + + .byte $06,$0c,$12,$18,$1e,$24,$2a,$30 + .byte $36,$3c,$42,$48,$4e,$54,$5a,$60 + .byte $07,$0e,$15,$1c,$23,$2a,$31,$38 + .byte $3f,$46,$4d,$54,$5b,$62,$69,$70 + + .byte $f8,$f0,$e8,$e0,$d8,$d0,$c8,$c0 + .byte $b8,$b0,$a8,$a0,$98,$90,$88,$80 + .byte $f9,$f2,$eb,$e4,$dd,$d6,$cf,$c8 + .byte $c1,$ba,$b3,$ac,$a5,$9e,$97,$90 + + .byte $fa,$f4,$ee,$e8,$e2,$dc,$d6,$d0 + .byte $ca,$c4,$be,$b8,$b2,$ac,$a6,$a0 + .byte $fb,$f6,$f1,$ec,$e7,$e2,$dd,$d8 + .byte $d3,$ce,$c9,$c4,$bf,$ba,$b5,$b0 + + .byte $fc,$f8,$f4,$f0,$ec,$e8,$e4,$e0 + .byte $dc,$d8,$d4,$d0,$cc,$c8,$c4,$c0 + .byte $fd,$fa,$f7,$f4,$f1,$ee,$eb,$e8 + .byte $e5,$e2,$df,$dc,$d9,$d6,$d3,$d0 + + .byte $fe,$fc,$fa,$f8,$f6,$f4,$f2,$f0 + .byte $ee,$ec,$ea,$e8,$e6,$e4,$e2,$e0 + .byte $ff,$fe,$fd,$fc,$fb,$fa,$f9,$f8 + .byte $f7,$f6,$f5,$f4,$f3,$f2,$f1,$f0 + +; +; Draw a list of lines using exclusive-or, which inverts the pixels. Drawing +; the same thing twice erases it. +; +; On entry: +; $45 - index of first line +; $46 - index of last line +; XCoord_0E/YCoord_0F or XCoord_10/YCoord_11 have transformed points in screen +; coordinates +; +; When the module is configured for OR-mode drawing, this code is replaced with +; a dedicated erase function. The erase code is nearly identical to the draw +; code, but saves a little time by simply zeroing out whole bytes instead of +; doing a read-modify-write. +; + +; Clear variables + +hptr = $06 +hpage = $18 ; hi-res page ($20 or $40) +xstart = $1c +ystart = $1d +xend = $1e +yend = $1f +delta_x = $3c +delta_y = $3d +line_adj = $3e +line_index = $43 +;ysave = $44 +first_line = $45 +last_line = $46 + +DrawLineListEOR: + ldx first_line ; 3 start with the first line in this object +DrawLoop: + lda LineStartPoint,X; 4+ get X0,Y0 + tay ; 2 +_0E_or_10_1: + lda XCoord0_0E,Y ; 4+ the instructions here are modified to load from + sta xstart ; 3 the appropriate set of X/Y coordinate tables +_0F_or_11_1: + lda YCoord0_0F,Y ; 4+ + sta ystart ; 3 + lda LineEndPoint,X ; 4+ get X1,Y1 + tay ; 2 +_0E_or_10_2: + lda XCoord0_0E,Y ; 4+ + sta xend ; 3 +_0F_or_11_2: + lda YCoord0_0F,Y ; 4+ + sta yend ; 3 + stx line_index ; 3 save this off + +; Prep the line draw code. We need to compute deltaX/deltaY, and set a register +; increment / decrement / no-op instruction depending on which way the line is +; going. + + lda xstart ; 3 compute delta X + sec ; 2 + sbc xend ; 3 + bcs L1A2F ; 2+ left to right + eor #$ff ; 2 right to left; invert value + adc #$01 ; 2 + ldy #OpINX ; 2 + bne GotDeltaX ; 3 + +L1A2F: + beq IsVertical ; 2+ branch if deltaX=0 + ldy #OpDEX ; 2 + bne GotDeltaX ; 3 + +IsVertical: + ldy #OpNOP ; 2 fully vertical, use no-op +GotDeltaX: + sta delta_x ; 3 + sty _InxDexNop1 ; 4 + sty _InxDexNop2 ; 4 + lda ystart ; 3 compute delta Y + sec ; 2 + sbc yend ; 3 + bcs L1A4E ; 2+ end < start, we're good + eor #$ff ; 2 invert value + adc #$01 ; 2 + ldy #OpINY ; 2 + bne GotDeltaY ; 3 + +L1A4E: + beq IsHorizontal ; 2+ branch if deltaY=0 + ldy #OpDEY ; 2 + bne GotDeltaY ; 3 + +IsHorizontal: + ldy #OpNOP ; 2 fully horizontal, use no-op +GotDeltaY: + sta delta_y ; 3 + sty _InyDeyNop1 ; 4 + sty _InyDeyNop2 ; 4 + ldx xstart ; 3 + ldy ystart ; 3 + lda #$00 ; 2 + sta line_adj ; 3 + lda delta_x ; 3 + cmp delta_y ; 3 + bcs HorizDomLine ; 2+ + +; Line draw: vertically dominant (move vertically every step) +; +; On entry: X=xpos, Y=ypos + +VertDomLine: + cpy yend ; 3 + beq LineDone ; 2+ +_InyDeyNop1: + nop ; 2 self-mod INY/DEY/NOP + lda YTableLo,Y ; 4+ new line, update Y position + sta hptr ; 3 + lda YTableHi,Y ; 4+ + ora hpage ; 3 + sta hptr+1 ; 3 + lda line_adj ; 3 Bresenham update + clc ; 2 + adc delta_x ; 3 + cmp delta_y ; 3 + bcs NewColumn ; 2+ + sta line_adj ; 3 + bcc SameColumn ; 3 + +NewColumn: + sbc delta_y ; 3 + sta line_adj ; 3 +_InxDexNop1: + nop ;2 self-mod INX/DEX/NOP +SameColumn: + sty ysave ; 3 + ldy Div7Tab,X ; 4+ XOR-draw the point + lda (hptr),Y ; 5+ + eor HiResBitTab,X ; 4+ + sta (hptr),Y ; 6 + ldy ysave ; 3 + jmp VertDomLine ; 3 + +LineDone: + ldx line_index ; 3 + inx ; 2 + cpx last_line ; 3 reached end? + beq DrawDone ; 2+ + jmp DrawLoop ; 3 + +DrawDone: + rts ; 6 + +; Line draw: horizontally dominant (move horizontally every step) +; +; On entry: X=xpos, Y=ypos + +HorizDomLine: + lda YTableLo,Y ; 4+ set up hi-res pointer + sta hptr ; 3 + lda YTableHi,Y ; 4+ + ora hpage ; 3 + sta hptr+1 ; 3 +HorzLoop: + cpx xend ; 3 X at end? + beq LineDone ; 2+ yes, finish +_InxDexNop2: + nop ; 2 + lda line_adj ; 3 Bresenham update + clc ; 2 + adc delta_y ; 3 + cmp delta_x ; 3 + bcs NewRow ; 2+ + sta line_adj ; 3 + bcc SameRow ; 3 + +NewRow: + sbc delta_x ; 3 + sta line_adj ; 3 +_InyDeyNop2: + nop ; 2 + lda YTableLo,Y ; 4+ update Y position + sta hptr ; 3 + lda YTableHi,Y ; 4+ + ora hpage ; 3 + sta hptr+1 ; 3 +SameRow: + sty ysave ; 3 + ldy Div7Tab,X ; 4+ XOR-draw the point + lda (hptr),Y ; 5+ + eor HiResBitTab,X ; 4+ + sta (hptr),Y ; 6 + ldy ysave ; 3 + jmp HorzLoop ; 3 + + ; Draw code calls here. Since we're configured for XOR mode, this just jumps to + ; the exclusive-or version. If we were configured for OR mode, this would be + ; LDX $45 / LDA $0B00,X instead of a JMP. +DrawLineList: + jmp DrawLineListEOR ; 3 + + ; + ; Unused OR-mode implementation follows. + ; + ; The code is substantially similar to the exclusive-or version, so it has not + ; been annotated. + ; +.byte $00,$0b ; ? + + tay ; 2 + lda XCoord0_0E,Y ; 4+ + sta xstart ; 3 + lda YCoord0_0F,Y ; 4+ + sta ystart ; 3 + lda LineEndPoint,X ; 4+ + tay ; 2 + lda XCoord0_0E,Y ; 4+ + sta xend ; 3 + lda YCoord0_0F,Y ; 4+ + sta yend ; 3 + stx line_index ; 3 + lda xstart ; 3 + sec ; 2 + sbc xend ; 3 + bcs L1B1A ; 2+ + eor #$ff ; 2 + adc #$01 ; 2 + ldy #$e8 ; 2 + bne L1B22 ; 3 + +L1B1A: + beq L1B20 ; 2+ + ldy #$ca ; 2 + bne L1B22 ; 3 + +L1B20: + ldy #$ea ; 2 +L1B22: + sta delta_x ; 3 + sty L1B79 ; 4 + sty L1BA6 ; 4 + lda ystart ; 3 + sec ; 2 + sbc yend ; 3 + bcs L1B39 ; 2+ + eor #$ff ; 2 + adc #$01 ; 2 + ldy #$c8 ; 2 + bne L1B41 ; 3 + +L1B39: + beq L1B3F ; 2+ + ldy #$88 ; 2 + bne L1B41 ; 3 + +L1B3F: + ldy #$ea ; 2 +L1B41: + sta delta_y ; 3 + sty L1B5B ; 4 + sty L1BB8 ; 4 + ldx xstart ; 3 + ldy ystart ; 3 + lda #$00 ; 2 + sta line_adj ; 3 + lda delta_x ; 3 + cmp delta_y ; 3 + bcs L1B96 ; 2+ +L1B57: + cpy yend ; 3 + beq L1B8B ; 2+ +L1B5B: + nop ; 2 + lda YTableLo,Y ; 4+ + sta hptr ; 3 + lda YTableHi,Y ; 4+ + ora hpage ; 3 + sta hptr+1 ; 3 + lda line_adj ; 3 + clc ; 2 + adc delta_x ; 3 + cmp delta_y ; 3 + bcs L1B75 ; 2+ + sta line_adj ; 3 + bcc L1B7A ; 3 + +L1B75: + sbc delta_y ; 3 + sta line_adj ; 3 +L1B79: + nop ; 2 +L1B7A: + sty ysave ; 3 + ldy Div7Tab,X ; 4+ + lda (hptr),Y ; 5+ + ora HiResBitTab,X ; 4+ + sta (hptr),Y ; 6 + ldy ysave ; 3 + jmp L1B57 ; 3 + +L1B8B: + ldx line_index ; 3 + inx ; 2 + cpx last_line ; 3 + beq L1B95 ; 2+ + jmp DrawLineList+2 ; 3 + +L1B95: + rts ; 6 + +L1B96: + lda YTableLo,Y ; 4+ + sta hptr ; 3 + lda YTableHi,Y ; 4+ + ora hpage ; 3 + sta hptr+1 ; 3 +L1BA2: + cpx xend ; 3 + beq L1B8B ; 2+ +L1BA6: + nop ; 2 + lda line_adj ; 3 + clc ; 2 + adc delta_y ; 3 + cmp delta_x ; 3 + bcs L1BB4 ; 2+ + sta line_adj ; 3 + bcc L1BC5 ; 3 + +L1BB4: + sbc delta_x ; 3 + sta line_adj ; 3 +L1BB8: + nop ; 2 + lda YTableLo,Y ; 4+ + sta hptr ; 3 + lda YTableHi,Y ; 4+ + ora hpage ; 3 + sta hptr+1 ; 3 +L1BC5: + sty ysave ; 3 + ldy Div7Tab,X ; 4+ + lda (hptr),Y ; 5+ + ora HiResBitTab,X ; 4+ + sta (hptr),Y ; 6 + ldy ysave ; 3 + jmp L1BA2 ; 3 + +; +; Unreferenced function that copies untransformed mesh X/Y values into the +; screen-coordinate buffers. Could be used for a static 2D effect, like a +; background that doesn't move. +; + ldx first_line ; 3 +UnusedCopyLoop: + lda ShapeXCoords,X ; 4+ + clc ; 2 + adc ystart ; 3 +_unused_mod0: + sta XCoord0_0E,X ; 5 + lda xend ; 3 + sec ; 2 + sbc ShapeYCoords,X ; 4+ +_unused_mod1: + sta YCoord0_0F,X ; 5 + inx ; 2 + cpx last_line ; 3 + bne UnusedCopyLoop ; 2+ + rts ; 6 + + ; Current hi-res page. + ; + ; $00 = draw page 1, show page 2 + ; $FF = draw page 2, show page 1 +CurPage: .byte $ff + + ; + ; Switch to the other hi-res page. + ; +SwapPage: + lda CurPage ; 4 + eor #$ff ; 2 flip to other page + sta CurPage ; 4 + beq DrawOnPage1 ; 3+ + sta TXTPAGE1 ; 4 draw on page 2, show page 1 + lda #$40 ; 2 + ldx #>XCoord1_10 ; 2 + ldy #>YCoord1_11 ; 2 + bne L1C0F ; 3 + +DrawOnPage1: + sta TXTPAGE2 ; 4 draw on page 1, show page 2 + lda #$20 ; 2 + ldx #>XCoord0_0E ; 2 + ldy #>YCoord0_0F ; 2 + + ; Save the hi-res page, and modify the instructions that read from or write data + ; to the transformed point arrays. +L1C0F: + sta hpage ; 3 + stx _0E_or_10_1+2 ; 4 + stx _0E_or_10_2+2 ; 4 + stx _0E_or_10_3+2 ; 4 + stx _unused_mod0+2 ; 4 + sty _0F_or_11_1+2 ; 4 + sty _0F_or_11_2+2 ; 4 + sty _0F_or_11_3+2 ; 4 + sty _unused_mod1+2 ; 4 + rts ; 6 + +; Unreferenced junk (12 bytes) +.byte $00,$00,$00,$00,$00,$00,$00,$00 +.byte $00,$00,$00,$00 + +; Coordinate transformation function. Transforms all points in a single object. +; +; On entry: +; 1c = scale (00-0f) +; 1d = xc (00-ff) +; 1e = yc (00-bf) +; 1f = zrot (00-1b) +; 3c = yrot (00-1b) +; 3d = xrot (00-1b) +; 45 = index of first point to transform +; 46 = index of last point to transform +; +; Rotation values greater than $1B, and scale factors greater than $0F, disable +; the calculation. This has the same effect as a rotation value of 0 or a scale +; of 15, but is more efficient, because this uses self-modifying code to skip +; the computation entirely. +; + +; Clear variables +xc = $19 ; transformed X coordinate +yc = $1a ; transformed Y coordinate +zc = $1b ; transformed Z coordinate +scale = $1c ; $00-0F, where $0F is full size +xposn = $1d ; X coordinate (0-255) +yposn = $1e ; Y coordinate (0-191) +zrot = $1f ; Z rotation ($00-1B) +yrot = $3c ; Y rotation ($00-1B) +xrot = $3d ; X rotation ($00-1B) +rot_tmp = $3f +out_index = $43 +first_point = $45 +last_point = $46 + +CompTransform: + ldx first_point ; 3 get first point index; this stays in X for a while + + ; Configure Z rotation. + + ldy zrot ; 3 + cpy #$1c ; 2 valid rotation value? + bcc ConfigZrot ; 2+ yes, configure + lda #DoTranslate ; 2 + sta _BeforeScale+2 ; 4 + bne TransformLoop ; 4 + +SetScale: + lda #DoScale ; 2 + sta _BeforeScale+2 ; 4 + lda ScaleIndexLo,Y ; 4+ $00, $10, $20, ... $F0 + sta _scaleLX+1 ; 4 + sta _scaleLY+1 ; 4 + lda ScaleIndexHi,Y ; 4+ $00, $01, $02, ... $0F + sta _scaleHX+1 ; 4 + sta _scaleHY+1 ; 4 + + + ; + ; Now that we've got the code modified, perform the computation for all points + ; in the object. + ; +TransformLoop: + lda ShapeXCoords,X ; 4+ + sta xc ; 3 + lda ShapeYCoords,X ; 4+ + sta yc ; 3 + lda ShapeZCoords,X ; 4+ + sta zc ; 3 + stx out_index ; 3 save for later +_BeforeZrot: + jmp DoZrot ; 3 + +DoZrot: + lda xc ; 3 rotating about Z, so we need to update X/Y coords + and #$0f ; 2 split X/Y into nibbles + sta rot_tmp ; 3 + lda xc ; 3 + and #$f0 ; 2 + sta rot_tmp+1 ; 3 + lda yc ; 3 + and #$0f ; 2 + sta rot_tmp+2 ; 3 + lda yc ; 3 + and #$f0 ; 2 + sta rot_tmp+3 ; 3 + ldy rot_tmp ; 3 transform X coord + ldx rot_tmp+1 ; 3 XC = X * cos(theta) - Y * sin(theta) +_zrotLC1: + lda RotTabLo,Y ; 4+ + clc ; 2 +_zrotHC1: + adc RotTabHi,X ; 4+ + ldy rot_tmp+2 ; 3 + ldx rot_tmp+3 ; 3 + sec ; 2 +_zrotLS1: + sbc RotTabLo,Y ; 4+ + sec ; 2 +_zrotHS1: + sbc RotTabHi,X ; 4+ + sta xc ; 3 save updated coord +_zrotLC2: + lda RotTabLo,Y ; 4+ transform Y coord + clc ; 2 YC = Y * cos(theta) + X * sin(theta) +_zrotHC2: + adc RotTabHi,X ; 4+ + ldy rot_tmp ; 3 + ldx rot_tmp+1 ; 3 + clc ; 2 +_zrotLS2: + adc RotTabLo,Y ; 4+ + clc ; 2 +_zrotHS2: + adc RotTabHi,X ; 4+ + sta yc ; 3 save updated coord +_BeforeYrot: + jmp DoYrot ; 3 + +DoYrot: + lda xc ; 3 rotating about Y, so update X/Z + and #$0f ; 2 + sta rot_tmp ; 3 + lda xc ; 3 + and #$f0 ; 2 + sta rot_tmp+1 ; 3 + lda zc ; 3 + and #$0f ; 2 + sta rot_tmp+2 ; 3 + lda zc ; 3 + and #$f0 ; 2 + sta rot_tmp+3 ; 3 + ldy rot_tmp ; 3 + ldx rot_tmp+1 ; 3 +_yrotLC1: + lda RotTabLo,Y ; 4+ + clc ; 2 +_yrotHC1: + adc RotTabHi,X ; 4+ + ldy rot_tmp+2 ; 3 + ldx rot_tmp+3 ; 3 + sec ; 2 +_yrotLS1: + sbc RotTabLo,Y ; 4+ + sec ; 2 +_yrotHS1: + sbc RotTabHi,X ; 4+ + sta xc ; 3 +_yrotLC2: + lda RotTabLo,Y ; 4+ + clc ; 2 +_yrotHC2: + adc RotTabHi,X ; 4+ + ldy rot_tmp ; 3 + ldx rot_tmp+1 ; 3 + clc ; 2 +_yrotLS2: + adc RotTabLo,Y ; 4+ + clc ; 2 +_yrotHS2: + adc RotTabHi,X ; 4+ + sta zc ; 3 +_BeforeXrot: + jmp DoXrot ; 3 + +DoXrot: + lda zc ; 3 rotating about X, so update Z/Y + and #$0f ; 2 + sta rot_tmp ; 3 + lda zc ; 3 + and #$f0 ; 2 + sta rot_tmp+1 ; 3 + lda yc ; 3 + and #$0f ; 2 + sta rot_tmp+2 ; 3 + lda yc ; 3 + and #$f0 ; 2 + sta rot_tmp+3 ; 3 + ldy rot_tmp ; 3 + ldx rot_tmp+1 ; 3 +_xrotLC1: + lda RotTabLo,Y ; 4+ + clc ; 2 +_xrotHC1: + adc RotTabHi,X ; 4+ + ldy rot_tmp+2 ; 3 + ldx rot_tmp+3 ; 3 + sec ; 2 +_xrotLS1: + sbc RotTabLo,Y ; 4+ + sec ; 2 +_xrotHS1: + sbc RotTabHi,X ; 4+ + sta zc ; 3 +_xrotLC2: + lda RotTabLo,Y ; 4+ + clc ; 2 +_xrotHC2: + adc RotTabHi,X ; 4+ + ldy rot_tmp ; 3 + ldx rot_tmp+1 ; 3 + clc ; 2 +_xrotLS2: + adc RotTabLo,Y ; 4+ + clc ; 2 +_xrotHS2: + adc RotTabHi,X ; 4+ + sta yc ; 3 +_BeforeScale: + jmp DoScale ; 3 + + + ; Apply scaling. Traditionally this is applied before rotation. +DoScale: + lda xc ; 3 scale the X coordinate + and #$f0 ; 2 + tax ; 2 + lda xc ; 3 + and #$0f ; 2 + tay ; 2 +_scaleLX: + lda ScaleTabLo,Y ; 4+ + clc ; 2 +_scaleHX: + adc ScaleTabHi,X ; 4+ + sta xc ; 3 + lda yc ; 3 scale the Y coordinate + and #$f0 ; 2 + tax ; 2 + lda yc ; 3 + and #$0f ; 2 + tay ; 2 +_scaleLY: + lda ScaleTabLo,Y ; 4+ + clc ; 2 +_scaleHY: + adc ScaleTabHi,X ; 4+ + sta yc ; 3 + + ; + ; Apply translation. + ; + ; This is the final step, so the result is written to the transformed-point + ; arrays. + ; +DoTranslate: + ldx out_index ; 3 + lda xc ; 3 + clc ; 2 + adc xposn ; 3 object center in screen coordinates +_0E_or_10_3: + sta XCoord0_0E,X ; 5 + lda yposn ; 3 + sec ; 2 + sbc yc ; 3 +_0F_or_11_3: + sta YCoord0_0F,X ; 5 + inx ; 2 + cpx last_point ; 3 done? + beq TransformDone ; 2+ yes, bail + jmp TransformLoop ; 3 + +TransformDone: + rts ; 6 + +SavedShapeIndex: + .byte $ad ;holds shape index while we work + +;******************************************************************************* +; CRUNCH/CRNCH% entry point * +; * +; For each object, do what CODE%(n) tells us to: * +; * +; 0 - do nothing * +; 1 - transform and draw * +; 2 - erase, transform, draw * +; 3 - erase * +;******************************************************************************* + +;first_line = $45 +;last_line = $46 + +CRUNCH: + jsr Setup ; 6 find Applesoft arrays + + ;============================== + ; First pass: erase old shapes + ;============================== + + lda NumObjects ; 4 number of defined objects + asl ; 2 * 2 + tax ; 2 use as index +ShapeLoop: + dex ; 2 + dex ; 2 + bmi Transform ; 2+ done +_codeAR1: + lda CODE_arr,X ; 4+ + cmp #$02 ; 2 2 or 3? + bcc ShapeLoop ; 2+ no, move on + stx SavedShapeIndex ; 4 + txa ; 2 + lsr ; 2 + tax ; 2 + lda FirstLineIndex,X; 4+ + sta first_line ; 3 + lda LastLineIndex,X ; 4+ + sta last_line ; 3 + cmp first_line ; 3 is number of lines <= 0? + bcc NoLines1 ; 2+ + beq NoLines1 ; 2+ yes, skip draw + jsr DrawLineListEOR ; 6 erase with EOR version, regardless of config +NoLines1: + ldx SavedShapeIndex ; 4 + bpl ShapeLoop ; 3 ...always + + ;=============================== + ; Second pass: transform shapes + ;=============================== +Transform: + lda NumObjects ; 4 + asl ; 2 + tax ; 2 +TransLoop: + dex ; 2 + dex ; 2 + bmi DrawNew ; 2+ +_codeAR2: + lda CODE_arr,X ; 4+ + beq TransLoop ; 2+ is it zero or three? + cmp #$03 ; 2 + beq TransLoop ; 2+ yes, we only draw on 1 or 2 + + ; Extract the scale, X/Y, and rotation values out of the arrays and copy them to + ; zero-page locations. + +_scaleAR: + lda SCALE_arr,X ; 4+ + sta scale ; 3 +_xAR: + lda X_arr,X ; 4+ + sta xposn ; 3 +_yAR: + lda Y_arr,X ; 4+ + sta yposn ; 3 +_zrotAR: + lda ZROT_arr,X ; 4+ + sta zrot ; 3 +_yrotAR: + lda YROT_arr,X ; 4+ + sta yrot ; 3 +_xrotAR: + lda XROT_arr,X ; 4+ + sta xrot ; 3 + stx SavedShapeIndex ; 4 save this off + txa ; 2 + lsr ; 2 convert to 1x index + tax ; 2 + lda FirstPointIndex,X; 4+ + sta first_line ; 3 (actually first_point) + lda LastPointIndex,X; 4+ + sta last_line ; 3 + cmp first_line ; 3 is number of points <= 0? + bcc NoPoints ; 2+ + beq NoPoints ; 2+ yes, skip transform + jsr CompTransform ; 6 transform all points +NoPoints: + ldx SavedShapeIndex ; 4 + lda xc ; 3 + clc ; 2 + adc xposn ; 3 +_sxAR: + sta SX_arr,X ; 5 + lda yposn ; 3 + sec ; 2 + sbc yc ; 3 +_syAR: + sta SY_arr,X ; 5 + jmp TransLoop ; 3 + + ;============================= + ; Third pass: draw shapes + ;============================= + +DrawNew: + lda NumObjects ; 4 + asl ; 2 + tax ; 2 +L1ECE: + dex ; 2 + dex ; 2 + bmi L1EF9 ; 2+ +_codeAR3: + lda CODE_arr,X ; 4+ is it 0 or 3? + beq L1ECE ; 2+ + cmp #$03 ; 2 + beq L1ECE ; 2+ yup, no draw + stx SavedShapeIndex ; 4 save index + txa ; 2 + lsr ; 2 convert it back to 1x index + tax ; 2 + lda FirstLineIndex,X; 4+ draw all the lines in the shape + sta first_line ; 3 + lda LastLineIndex,X ; 4+ + sta last_line ; 3 + cmp first_line ; 3 is number of lines <= 0? + bcc NoLines2 ; 2+ + beq NoLines2 ; 2+ yes, skip draw + jsr DrawLineList ; 6 draw all lines +NoLines2: + ldx SavedShapeIndex ; 4 + bpl L1ECE ; 3 ...always + +L1EF9: + jmp SwapPage ; 3 + + +;******************************************************************************* +; RESET entry point * +; * +; Zeroes out the CODE% array, erases both hi-res screens, and enables display * +; of the primary hi-res page. * +;******************************************************************************* + +RESET: + jsr Setup ; 6 sets A=0, Y=$1E +_codeAR4: + sta CODE_arr,y ; 5 zero out CODE% + dey ; 2 + bpl _codeAR4 ; 3+ + jsr CLEAR ; 6 + jsr SwapPage ; 6 + jsr SwapPage ; 6 + rts ; 6 + +;******************************************************************************* +; CLEAR/CLR% entry point * +; * +; Clears both hi-res pages. * +;******************************************************************************* +; Clear variables + +ptr1 = $1a +ptr2 = $1c + +CLEAR: + lda #$20 ; 2 hi-res page 1 + sta ptr1+1 ; 3 + lda #$40 ; 2 hi-res page 2 + sta ptr2+1 ; 3 + ldy #$00 ; 2 + sty ptr1 ; 3 + sty ptr2 ; 3 +L1F1D: + tya ; 2 +L1F1E: + sta (ptr1),Y ; 6 erase both pages + sta (ptr2),Y ; 6 + iny ; 2 + bne L1F1E ; 2+ + inc ptr1+1 ; 5 + inc ptr2+1 ; 5 + lda ptr1+1 ; 3 (could hold counter in X-reg) + and #$3f ; 2 + bne L1F1D ; 2+ + +;******************************************************************************* +; HIRES entry point * +; * +; Displays primary hi-res page. * +;******************************************************************************* +HI_RES: + sta HIRES ; 4 + sta MIXCLR ; 4 + sta TXTCLR ; 4 + rts ; 6 + +; Locate Applesoft arrays. This assumes the arrays are declared first, and in +; the correct order, so that the start can be found at a fixed offset from the +; BASIC array table pointer. +; +; 1 DIM CODE%(15), X%(15), Y%(15), SCALE%(15), XROT%(15), YROT%(15), ZROT%(15), +; SX%(15), SY%(15) +; +; If you generate the module for Integer BASIC, this is the entry point for +; MISSILE (7993). + +Setup: + lda BAS_ARYTAB ; 3 CODE% is at +$0008 + clc ; 2 + adc #$08 ; 2 + tax ; 2 + lda BAS_ARYTAB+1 ; 3 + adc #$00 ; 2 + stx _codeAR1+1 ; 4 + sta _codeAR1+2 ; 4 + stx _codeAR2+1 ; 4 + sta _codeAR2+2 ; 4 + stx _codeAR3+1 ; 4 + sta _codeAR3+2 ; 4 + stx _codeAR4+1 ; 4 + sta _codeAR4+2 ; 4 + lda BAS_ARYTAB ; 3 X% is at +$002F + clc ; 2 + adc #$2f ; 2 + tax ; 2 + lda BAS_ARYTAB+1 ; 3 + adc #$00 ; 2 + stx _xAR+1 ; 4 + sta _xAR+2 ; 4 + lda BAS_ARYTAB ; 3 Y% is at +$0056 + clc ; 2 + adc #$56 ; 2 + tax ; 2 + lda BAS_ARYTAB+1 ; 3 + adc #$00 ; 2 + stx _yAR+1 ; 4 + sta _yAR+2 ; 4 + lda BAS_ARYTAB ; 3 SCALE% is at + $007D + clc ; 2 + adc #$7d ; 2 + tax ; 2 + lda BAS_ARYTAB+1 ; 3 + adc #$00 ; 2 + stx _scaleAR+1 ; 4 + sta _scaleAR+2 ; 4 + lda BAS_ARYTAB ; 3 XROT% is at +$00A4 + clc ; 2 + adc #$a4 ; 2 + tax ; 2 + lda BAS_ARYTAB+1 ; 3 + adc #$00 ; 2 + stx _xrotAR+1 ; 4 + sta _xrotAR+2 ; 4 + lda BAS_ARYTAB ; 3 YROT% is at +$00CB + clc ; 2 + adc #$cb ; 2 + tax ; 2 + lda BAS_ARYTAB+1 ; 3 + adc #$00 ; 2 + stx _yrotAR+1 ; 4 + sta _yrotAR+2 ; 4 + lda BAS_ARYTAB ; 3 ZROT% is at +$00F2 + clc ; 2 + adc #$f2 ; 2 + tax ; 2 + lda BAS_ARYTAB+1 ; 3 + adc #$00 ; 2 + stx _zrotAR+1 ; 4 + sta _zrotAR+2 ; 4 + lda BAS_ARYTAB ; 3 SX% is at +$0119 + clc ; 2 + adc #$19 ; 2 + tax ; 2 + lda BAS_ARYTAB+1 ; 3 + adc #$01 ; 2 + stx _sxAR+1 ; 4 + sta _sxAR+2 ; 4 + lda BAS_ARYTAB ; 3 SY% is at +$0140 + clc ; 2 + adc #$40 ; 2 + tax ; 2 + lda BAS_ARYTAB+1 ; 3 + adc #$01 ; 2 + stx _syAR+1 ; 4 + sta _syAR+2 ; 4 + ldy #$1e ; 2 Set A and Y for RESET + lda #$00 ; 2 + rts ; 6 + + ; Junk; pads binary to end of page. +.align $0100 + diff --git a/music/zero_wing/Makefile b/music/zero_wing/Makefile new file mode 100644 index 00000000..ecada150 --- /dev/null +++ b/music/zero_wing/Makefile @@ -0,0 +1,33 @@ +include ../../Makefile.inc + +DOS33 = ../../utils/dos33fs-utils/dos33 +EMPTY_DISK = ../../empty_disk/empty.dsk +TOKENIZE = ../../utils/asoft_basic-utils/tokenize_asoft + +all: zw.dsk + +zw.dsk: HELLO ZW + cp $(EMPTY_DISK) zw.dsk + $(DOS33) -y zw.dsk SAVE A HELLO + $(DOS33) -y zw.dsk BSAVE -a 0x6000 ZW + +#### + +ZW: zw.o + ld65 -o ZW zw.o -C ../../linker_scripts/apple2_6000.inc + +zw.o: zw.s zx02_optim.s \ + text_print.s \ + zp.inc hardware.inc + ca65 -o zw.o zw.s -l zw.lst + +#### + +HELLO: hello.bas + $(TOKENIZE) < hello.bas > HELLO + +### + + +clean: + rm -f *~ *.o *.lst HELLO ZW diff --git a/music/zero_wing/gr_offsets.s b/music/zero_wing/gr_offsets.s new file mode 100644 index 00000000..d3af91f7 --- /dev/null +++ b/music/zero_wing/gr_offsets.s @@ -0,0 +1,5 @@ +gr_offsets: + .word $400,$480,$500,$580,$600,$680,$700,$780 + .word $428,$4a8,$528,$5a8,$628,$6a8,$728,$7a8 + .word $450,$4d0,$550,$5d0,$650,$6d0,$750,$7d0 + diff --git a/music/zero_wing/graphics/Makefile b/music/zero_wing/graphics/Makefile new file mode 100644 index 00000000..cfb9485f --- /dev/null +++ b/music/zero_wing/graphics/Makefile @@ -0,0 +1,37 @@ +include ../../../Makefile.inc + +ZX02 = ~/research/6502_compression/zx02.git/build/zx02 +PNG_TO_HGR = ../../../utils/hgr-utils/png2hgr + +all: cats.hgr.zx02 captain.hgr.zx02 operator.hgr.zx02 + +#### + +cats.hgr.zx02: cats.hgr + $(ZX02) cats.hgr cats.hgr.zx02 + +cats.hgr: cats.png + $(PNG_TO_HGR) cats.png > cats.hgr + +#### + +captain.hgr.zx02: captain.hgr + $(ZX02) captain.hgr captain.hgr.zx02 + +captain.hgr: captain.png + $(PNG_TO_HGR) captain.png > captain.hgr + +#### + +operator.hgr.zx02: operator.hgr + $(ZX02) operator.hgr operator.hgr.zx02 + +operator.hgr: operator.png + $(PNG_TO_HGR) operator.png > operator.hgr + + + +#### + +clean: + rm -f *~ diff --git a/music/zero_wing/graphics/captain.png b/music/zero_wing/graphics/captain.png new file mode 100644 index 0000000000000000000000000000000000000000..ab08767146f4c165f6209bfc52474121e93b5d9d GIT binary patch literal 2432 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 + +.include "zp.inc" +.include "hardware.inc" + +hires_start: + + ;=================== + ; set graphics mode + ;=================== + jsr HOME + + jsr HGR + + ;=================== + ; Load graphics + ;=================== +load_loop: + + ;============================= + ; OPERATOR + ;============================= + + jsr HOME + + lda #operator_data + sta zx_src_h+1 + + lda #$20 + + jsr zx02_full_decomp + + lda #operator_text + sta OUTH + + jsr move_and_print + jsr move_and_print + + jsr wait_until_keypress + + + ;============================= + ; CATS + ;============================= + + jsr HOME + + lda #cats_data + sta zx_src_h+1 + + lda #$20 + + jsr zx02_full_decomp + + lda #cats_text + sta OUTH + + jsr move_and_print + + jsr wait_until_keypress + + ;============================= + ; CAPTAIN + ;============================= + + jsr HOME + + lda #captain_data + sta zx_src_h+1 + + lda #$20 + + jsr zx02_full_decomp + + lda #captain_text + sta OUTH + + jsr move_and_print + + jsr wait_until_keypress + + + + + + jmp load_loop + + + + +.align $100 + .include "wait_keypress.s" + .include "zx02_optim.s" + .include "text_print.s" + .include "gr_offsets.s" + +cats_data: + .incbin "graphics/cats.hgr.zx02" + +cats_text: + .byte 0,21,"CATS: HOW ARE YOU GENTLEMEN !!",0 + +captain_data: + .incbin "graphics/captain.hgr.zx02" + +captain_text: + .byte 0,21,"CAPTAIN: WHAT YOU SAY !!",0 + +operator_data: + .incbin "graphics/operator.hgr.zx02" + +operator_text: + .byte 0,20,"OPERATOR: WE GET SIGNAL.",0 + .byte 1,22,"CAPTAIN: WHAT !",0 diff --git a/music/zero_wing/zx02_optim.s b/music/zero_wing/zx02_optim.s new file mode 100644 index 00000000..5eebc2e0 --- /dev/null +++ b/music/zero_wing/zx02_optim.s @@ -0,0 +1,159 @@ +; De-compressor for ZX02 files +; ---------------------------- +; +; Decompress ZX02 data (6502 optimized format), optimized for speed and size +; 138 bytes code, 58.0 cycles/byte in test file. +; +; Compress with: +; zx02 input.bin output.zx0 +; +; (c) 2022 DMSC +; Code under MIT license, see LICENSE file. + + +;ZP=$80 + +;offset = ZP+0 +;ZX0_src = ZP+2 +;ZX0_dst = ZP+4 +;bitr = ZP+6 +;pntr = ZP+7 + + ; Initial values for offset, source, destination and bitr +;zx0_ini_block: +; .byte $00, $00, comp_data, out_addr, $80 + +;-------------------------------------------------- +; Decompress ZX0 data (6502 optimized format) + +zx02_full_decomp: +; ; Get initialization block +; ldy #7 +; +;copy_init: lda zx0_ini_block-1, y +; sta offset-1, y +; dey +; bne copy_init + + + sta ZX0_dst+1 ; page to output to in A +zx_src_l: + ldy #$dd + sty ZX0_src +zx_src_h: + ldy #$dd + sty ZX0_src+1 + ldy #$80 + sty bitr + ldy #0 + sty offset + sty offset+1 + sty ZX0_dst ; always on even page + +; Decode literal: Ccopy next N bytes from compressed file +; Elias(length) byte[1] byte[2] ... byte[N] +decode_literal: + jsr get_elias + +cop0: lda (ZX0_src), y + inc ZX0_src + bne plus1 + inc ZX0_src+1 +plus1: sta (ZX0_dst),y + inc ZX0_dst + bne plus2 + inc ZX0_dst+1 +plus2: dex + bne cop0 + + asl bitr + bcs dzx0s_new_offset + +; Copy from last offset (repeat N bytes from last offset) +; Elias(length) + jsr get_elias +dzx0s_copy: + lda ZX0_dst + sbc offset ; C=0 from get_elias + sta pntr + lda ZX0_dst+1 + sbc offset+1 + sta pntr+1 + +cop1: + lda (pntr), y + inc pntr + bne plus3 + inc pntr+1 +plus3: sta (ZX0_dst),y + inc ZX0_dst + bne plus4 + inc ZX0_dst+1 +plus4: dex + bne cop1 + + asl bitr + bcc decode_literal + +; Copy from new offset (repeat N bytes from new offset) +; Elias(MSB(offset)) LSB(offset) Elias(length-1) +dzx0s_new_offset: + ; Read elias code for high part of offset + jsr get_elias + beq exit ; Read a 0, signals the end + ; Decrease and divide by 2 + dex + txa + lsr ; @ + sta offset+1 + + ; Get low part of offset, a literal 7 bits + lda (ZX0_src), y + inc ZX0_src + bne plus5 + inc ZX0_src+1 +plus5: + ; Divide by 2 + ror ; @ + sta offset + + ; And get the copy length. + ; Start elias reading with the bit already in carry: + ldx #1 + jsr elias_skip1 + + inx + bcc dzx0s_copy + +; Read an elias-gamma interlaced code. +; ------------------------------------ +get_elias: + ; Initialize return value to #1 + ldx #1 + bne elias_start + +elias_get: ; Read next data bit to result + asl bitr + rol ; @ + tax + +elias_start: + ; Get one bit + asl bitr + bne elias_skip1 + + ; Read new bit from stream + lda (ZX0_src), y + inc ZX0_src + bne plus6 + inc ZX0_src+1 +plus6: ;sec ; not needed, C=1 guaranteed from last bit + rol ;@ + sta bitr + +elias_skip1: + txa + bcs elias_get + ; Got ending bit, stop reading +exit: + rts