dos33fsprogs/graphics/hgr/budge3d/ship_cube.s

1896 lines
56 KiB
ArmAsm

;============================================================================
; 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 #<TextOut ; 2
sty MON_CSWL ; 3
rts ; 6
;*******************************************************************************
; Draw a character. This function preserves the contents of the registers, *
; going so far as to avoid using the X register entirely, which makes the code *
; less efficient than it could be. *
; *
; One uncommon feature: this draws on both hi-res screens at the same time. *
;*******************************************************************************
ysave = $00
ytmp = $01
glyph_ptr = $26
hbasl = $2a
DrawChar:
pha ; 3 save original char
sty ysave ; 3
cmp #$8d ; 2 carriage return?
beq NewLine ; 2/3 yes, don't output a glyph
; Compute Y coordinate.
; This is simpler than the full HPOSN because the line
; we're interested in is a multiple of 8.
; (This could have used the Y-lookup table in the module.)
lda MON_CV ; 3 vtab
lsr ; 2
and #$03 ; 2
ora #$20 ; 2
sta hbasl+1 ; 3
lda MON_CV ; 3
ror ; 2
php ; 3
asl ; 2
and #$18 ; 2
sta hbasl ; 3
asl ; 2
asl ; 2
ora hbasl ; 3
asl ; 2
plp ; 4
ror ; 2
clc ; 2
adc MON_CH ; 3 htab
sta hbasl ; 3
; Now compute the address of the glyph.
pla ; 4 recover original char
and #$7f ; 2 (this was done by the caller)
pha ; 3 save it again
lda #$00 ; 2 (why not use Y-reg?)
sta glyph_ptr+1 ; 3
pla ; 4
pha ; 3
rol ; 2 multiply by 8
rol glyph_ptr+1 ; 5
rol ; 2
rol glyph_ptr+1 ; 5
rol ; 2
rol glyph_ptr+1 ; 5
sta glyph_ptr ; 3
lda glyph_ptr+1 ; 3
clc ; 2
adc #>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 #<DoYrot ; 2 no, modify code to skip Z-rot
sta _BeforeZrot+1 ; 4
bne NoZrot ; 3
ConfigZrot:
lda #<DoZrot ; 2
sta _BeforeZrot+1 ; 4
lda RotIndexLo_sin,Y ; 4+
sta _zrotLS1+1 ; 4
sta _zrotLS2+1 ; 4
lda RotIndexHi_sin,Y ; 4+
sta _zrotHS1+1 ; 4
sta _zrotHS2+1 ; 4
lda RotIndexLo_cos,Y ; 4+
sta _zrotLC1+1 ; 4
sta _zrotLC2+1 ; 4
lda RotIndexHi_cos,Y ; 4+
sta _zrotHC1+1 ; 4
sta _zrotHC2+1 ; 4
; Configure Y rotation.
NoZrot:
ldy yrot ; 3
cpy #$1c ; 2 valid rotation value?
bcc ConfigYrot ; 2+ yes, configure
lda #<DoXrot ; 2 no, modify code to skip Y-rot
sta _BeforeYrot+1 ; 4
bne NoYrot ; 3
ConfigYrot:
lda #<DoYrot ; 2
sta _BeforeYrot+1 ; 4
lda RotIndexLo_sin,Y ; 4+
sta _yrotLS1+1 ; 4
sta _yrotLS2+1 ; 4
lda RotIndexHi_sin,Y ; 4+
sta _yrotHS1+1 ; 4
sta _yrotHS2+1 ; 4
lda RotIndexLo_cos,Y ; 4+
sta _yrotLC1+1 ; 4
sta _yrotLC2+1 ; 4
lda RotIndexHi_cos,Y ; 4+
sta _yrotHC1+1 ; 4
sta _yrotHC2+1 ; 4
; Configure X rotation.
NoYrot:
ldy xrot ; 3
cpy #$1c ; 2 valid rotation value?
bcc ConfigXrot ; 2+ yes, configure
lda #<DoScale ; 2 no, modify code to skip X-rot
sta _BeforeXrot+1 ; 4
bne ConfigScale ; 3
ConfigXrot:
lda #<DoXrot ; 2
sta _BeforeXrot+1 ; 4
lda RotIndexLo_sin,Y ; 4+
sta _xrotLS1+1 ; 4
sta _xrotLS2+1 ; 4
lda RotIndexHi_sin,Y ; 4+
sta _xrotHS1+1 ; 4
sta _xrotHS2+1 ; 4
lda RotIndexLo_cos,Y ; 4+
sta _xrotLC1+1 ; 4
sta _xrotLC2+1 ; 4
lda RotIndexHi_cos,Y ; 4+
sta _xrotHC1+1 ; 4
sta _xrotHC2+1 ; 4
; Configure scaling.
ConfigScale:
ldy scale ; 3
cpy #$10 ; 2 valid scale value?
bcc SetScale ; 2+ yes, configure it
lda #<DoTranslate ; 2 no, skip it
sta _BeforeScale+1 ; 4
lda #>DoTranslate ; 2
sta _BeforeScale+2 ; 4
bne TransformLoop ; 4
SetScale:
lda #<DoScale ; 2
sta _BeforeScale+1 ; 4
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