diff --git a/graphics/hgr/budge3d/Makefile b/graphics/hgr/budge3d/Makefile index 9c891078..3ed3216e 100644 --- a/graphics/hgr/budge3d/Makefile +++ b/graphics/hgr/budge3d/Makefile @@ -7,10 +7,9 @@ EMPTY_DISK = ../../../empty_disk all: budge3d.dsk -budge3d.dsk: HELLO TEST SHIP_CUBE +budge3d.dsk: HELLO SHIP_CUBE cp $(EMPTY_DISK)/empty.dsk budge3d.dsk $(DOS33) -y budge3d.dsk SAVE A HELLO - $(DOS33) -y budge3d.dsk SAVE A TEST $(DOS33) -y budge3d.dsk BSAVE -a 0x300 SHIP_CUBE @@ -19,10 +18,6 @@ budge3d.dsk: HELLO TEST SHIP_CUBE HELLO: hello.bas $(TOKENIZE) < hello.bas > HELLO -### - -TEST: test.bas - $(TOKENIZE) < test.bas > TEST #### @@ -32,9 +27,9 @@ SHIP_CUBE: ship_cube.o ship_cube.o: ship_cube.s \ zp.inc hardware.inc \ shapes.s math_constants.s hgr_tables.s \ - hgr_textgen.s scale_constants.s + scale_constants.s ca65 -o ship_cube.o ship_cube.s -l ship_cube.lst #### clean: - rm -f *~ *.o *.lst HELLO SHIP_CUBE TEST + rm -f *~ *.o *.lst HELLO SHIP_CUBE diff --git a/graphics/hgr/budge3d/asm_example/Makefile b/graphics/hgr/budge3d/asm_example/Makefile new file mode 100644 index 00000000..98d69639 --- /dev/null +++ b/graphics/hgr/budge3d/asm_example/Makefile @@ -0,0 +1,35 @@ +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 \ + zp.inc hardware.inc \ + shapes.s math_constants.s hgr_tables.s \ + scale_constants.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/asm_example/budge3d.dsk b/graphics/hgr/budge3d/asm_example/budge3d.dsk new file mode 100644 index 00000000..5d050475 Binary files /dev/null and b/graphics/hgr/budge3d/asm_example/budge3d.dsk differ diff --git a/graphics/hgr/budge3d/asm_example/hardware.inc b/graphics/hgr/budge3d/asm_example/hardware.inc new file mode 100644 index 00000000..db86e1b0 --- /dev/null +++ b/graphics/hgr/budge3d/asm_example/hardware.inc @@ -0,0 +1,17 @@ +;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 + diff --git a/graphics/hgr/budge3d/asm_example/hello.bas b/graphics/hgr/budge3d/asm_example/hello.bas new file mode 100644 index 00000000..fba2ddfb --- /dev/null +++ b/graphics/hgr/budge3d/asm_example/hello.bas @@ -0,0 +1,2 @@ +10 PRINT CHR$ (4)"BRUN SHIP_CUBE" + diff --git a/graphics/hgr/budge3d/asm_example/hgr_tables.s b/graphics/hgr/budge3d/asm_example/hgr_tables.s new file mode 100644 index 00000000..3fa45f1d --- /dev/null +++ b/graphics/hgr/budge3d/asm_example/hgr_tables.s @@ -0,0 +1,102 @@ +; +; 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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40 + .byte $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) + diff --git a/graphics/hgr/budge3d/asm_example/math_constants.s b/graphics/hgr/budge3d/asm_example/math_constants.s new file mode 100644 index 00000000..a0e38fa5 --- /dev/null +++ b/graphics/hgr/budge3d/asm_example/math_constants.s @@ -0,0 +1,68 @@ +; +; 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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $f0,$f0,$f2,$f3,$f6,$f9,$fc,$00,$04,$07,$0a,$0d,$0e,$10,$10,$00 + diff --git a/graphics/hgr/budge3d/asm_example/scale_constants.s b/graphics/hgr/budge3d/asm_example/scale_constants.s new file mode 100644 index 00000000..a6eafba1 --- /dev/null +++ b/graphics/hgr/budge3d/asm_example/scale_constants.s @@ -0,0 +1,113 @@ +; +; 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 + diff --git a/graphics/hgr/budge3d/asm_example/shapes.s b/graphics/hgr/budge3d/asm_example/shapes.s new file mode 100644 index 00000000..5968f815 --- /dev/null +++ b/graphics/hgr/budge3d/asm_example/shapes.s @@ -0,0 +1,208 @@ +;=========================================================== +; +; 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: + + ; spaceship + + .byte $c4,$c7,$c7,$c7,$c7,$d6,$d6,$d6 ; $00 + .byte $d6,$f1,$f1,$00,$00,$15,$15,$1e ; $08 + .byte $1e,$1e,$1e,$24,$24,$24,$24,$09 ; $10 + .byte $1b,$15,$1e ; $18 + + ; cube + .byte $fb,$05,$05,$fb,$fb ; $1b + .byte $05,$05,$fb ; $20 + + ; junk + + .byte $ec,$fc,$0c,$18,$28,$30,$44,$50,$74,$7c,$05,$fb,$00,$c4,$ca,$ca,$ca,$ca,$d6,$d6,$d6,$d6,$f1,$f1,$00,$00,$15,$15,$1e + .byte $1e,$1e,$1e,$24,$24,$24,$24,$09,$1b,$15,$1e,$d8,$e8,$f8,$08,$18,$28,$9c,$c4,$ec,$14,$3c,$64,$c9,$37,$b5,$4b,$22,$de,$de,$f2,$0e + .byte $22,$22,$de,$de,$f2,$0e,$22,$28,$39,$46,$d8,$c7,$ba,$00,$00,$00,$4d,$4d,$3f,$3f,$b3,$b3,$c1,$c1,$f9,$07,$07,$f9,$11,$ef,$ef,$11 + .byte $08,$f8,$0a,$f6,$19,$e7,$19,$e7,$00,$fa,$06,$00,$00,$fc,$04,$fc,$04,$fa,$06,$f6,$0a,$fc,$04,$f4,$0c,$fa,$06,$fa,$06,$f6,$0a,$f6 + .byte $0a,$f4,$0c,$f4,$0c,$d0,$30,$d0,$30,$d0,$30,$d0,$30,$d0,$30,$d0,$30,$d3,$06,$fc,$1a,$ba,$00,$da,$03,$16,$1a,$b0,$00,$ba,$02,$10 + .byte $34,$1a,$98,$19,$2b,$da,$03,$1b,$ab,$3b,$a0,$a0,$ab,$a4,$01,$df,$82,$d9,$0b,$f2,$0c,$d8,$06,$06,$2b,$7c,$10,$5b,$08,$3f,$19,$16 + .byte $0f,$01,$9c,$19,$23,$0f,$01,$97,$f2,$18,$24,$00,$0c,$c0,$f8,$06,$ed,$2b,$7c,$42,$1a,$ac,$00,$ba,$5c,$06,$f1,$1a,$03,$00,$da,$06 + +; 3D mesh Y coordinates (0, 3, ...) +ShapeYCoords: + ; spaceship + .byte $00,$03,$03,$fd,$fd,$06,$09,$fa + .byte $f7,$09,$f7,$0f,$f1,$24,$dc,$24 + .byte $dc,$09,$f7,$09,$f7,$06,$fa,$00 + .byte $00,$00,$00 + + ; cube + .byte $fb,$fb,$05,$05,$fb + .byte $fb,$05,$05 + + ; garbage + .byte $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: + ; spaceship + .byte $00,$03,$fd,$03,$fd,$09,$fa,$09 + .byte $fa,$fa,$fa,$fa,$fa,$fa,$fa,$fa + .byte $fa,$fa,$fa,$fa,$fa,$09,$09,$09 + .byte $09,$1b,$1b + + ; cube + .byte $fb,$fb,$fb,$fb,$05 + .byte $05,$05,$05 + + ; garbage + .byte $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 + ; spaceship (29 lines) + .byte $00,$00,$00,$00,$01,$02,$03,$04 + .byte $06,$08,$09,$0a,$0b,$0c,$0d,$0e + .byte $0f,$10,$11,$12,$13,$05,$07,$13 + .byte $14,$15,$17,$19,$1a + + ; cube (12 lines) + .byte $1b,$1c,$1d + .byte $1e,$1f,$20,$21,$22,$1b,$1c,$1d + .byte $1e + + ; junk + .byte $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 + + ; spaceship (29 lines) + .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 + + ; cube (12 lines) + .byte $1c,$1d,$1e + .byte $1b,$20,$21,$22,$1f,$1f,$20,$21 + .byte $22 + + ; junk + .byte $27,$28,$29,$2a,$2b,$2c,$2f,$2f,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f + .byte $40,$41,$42,$43,$44,$44,$45,$46,$45,$46,$46,$49,$4a,$4a,$51,$52,$53,$54,$55,$56,$50,$58,$5a,$56,$5e,$64,$63,$64,$60,$66,$65,$66 + .byte $67,$67,$68,$68,$69,$6a,$6a,$6b,$6b,$6c,$6d,$6d,$6e,$6e,$6f,$71,$72,$73,$70,$75,$76,$77,$74,$79,$7a,$7b,$78,$7d,$7e,$7f,$7c,$82 + .byte $83,$81,$80,$85,$84,$80,$81,$60,$5d,$84,$85,$89,$8a,$8b,$8d,$8e,$8f,$90,$91,$92,$93,$94,$95,$96,$97,$98,$9b,$9c,$99,$9a,$9a,$9b + .byte $9c,$9b,$9c,$a5,$a9,$ad,$a7,$ab,$af,$a6,$aa,$ae,$a8,$ac,$b0,$10,$dd,$08,$3f,$19,$6b,$0f,$00,$20,$d0,$09,$20,$0c,$fd,$c9,$d3,$66 + .byte $33,$20,$ce,$0a,$a9,$ff,$85,$2f,$d0,$00,$20,$61,$0c,$20,$89,$f6,$11,$00,$02,$29,$d4,$06,$04,$49,$51,$01,$f8,$4a,$06,$03,$51,$01 + .byte $fa,$21,$3a,$f2,$42,$51,$d3,$07,$fb,$19,$00,$02,$11,$7c,$03,$24,$71,$2a,$71,$00,$20,$7b,$0d,$24,$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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $10,$20,$30,$40,$50,$60,$70,$80 + .byte $90,$a0,$b0,$c0,$d0,$e0,$d0,$c0 + .byte $b0,$a0,$90,$80 + +RotIndexHi_sin: + .byte $07,$06,$05,$04,$03,$02,$01,$00 + .byte $01,$02,$03,$04,$05,$06,$07,$08 + .byte $09,$0a,$0b,$0c,$0d,$0e,$0d,$0c + .byte $0b,$0a,$09,$08 + +RotIndexLo_cos: + .byte $00,$10,$20,$30,$40,$50,$60,$70 + .byte $80,$90,$a0,$b0,$c0,$d0,$e0,$d0 + .byte $c0,$b0,$a0,$90,$80,$70,$60,$50 + .byte $40,$30,$20,$10 + +RotIndexHi_cos: + .byte $00,$01,$02,$03,$04,$05,$06,$07 + .byte $08,$09,$0a,$0b,$0c,$0d,$0e,$0d + .byte $0c,$0b,$0a,$09,$08,$07,$06,$05 + .byte $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) + diff --git a/graphics/hgr/budge3d/asm_example/ship_cube.s b/graphics/hgr/budge3d/asm_example/ship_cube.s new file mode 100644 index 00000000..fcca6fba --- /dev/null +++ b/graphics/hgr/budge3d/asm_example/ship_cube.s @@ -0,0 +1,1269 @@ +;============================================================================ +; 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 + +; This makes extensive use of self-modifying code. Labels that begin with an +; underscore indicate self-modification targets. + +; Note from Vince Weaver +; + I've taken the disassembly and am converting it to assembly language +; I guess it might make more sense to get an assembly language kernel +; from the program, but I'm going to modify the BASIC anyway + + + +;=========================================================================== +; +; You can define up to 16 shapes. Their parameters are stored in the various +; arrays: +; +; CODE_arr+N: 0 (do nothing), 1 (transform & draw), 2 (erase previous, +; transform, draw new), 3 (erase). +; X_arr+N: X coordinate of center (0-255). +; Y_arr+N: Y coordinate of center (0-191). +; SCALE_arr+N: scale factor, 0-15. 15 is full size, 0 is 1/16th. +; XROT_arr+N: rotation about X axis, 0-27. 0 is no rotation, 27 is just shy +; of 360 degrees. +; YROT_arr+N: rotation about Y axis. +; ZROT_arr+N: rotation about Z axis. +; SX_arr+N: (output) X coordinate of last point drawn. +; SY_arr+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. +; CRUNCH: 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 +;============================================================================ + +.include "zp.inc" + +.include "hardware.inc" + +; org $0300 + +entry: + jsr RESET + + ; CODE[0]=1 -> transform and draw + ; CODE[1]=1 -> transform and draw + + lda #1 + sta CODE_arr + sta CODE_arr+1 + + ; X[0]=127 Y[0]=96:X[1]=20:Y[1]=30 -> co-ord of center + + lda #127 + sta X_arr + lda #96 + sta Y_arr + + lda #20 + sta X_arr+1 + lda #30 + sta Y_arr+1 + + ; SCALE[0]=15:XROT[0]=2:YROT[0]=5:ZROT[0]=0 + ; SCALE[1]=15:XROT[1]=2:YROT[1]=5:ZROT[1]=0 + + lda #15 + sta SCALE_arr + sta SCALE_arr+1 + + lda #2 + sta XROT_arr + sta XROT_arr+1 + + lda #5 + sta YROT_arr + sta YROT_arr+1 + + lda #0 + sta ZROT_arr + sta ZROT_arr+1 + + jsr CRUNCH + jsr CRUNCH + + ; CODE[0]=2:CODE[1]=2 -> erase and draw new + + lda #2 + sta CODE_arr + sta CODE_arr+1 + +loop: + ; ZROT[0]+=1: IF ZEROT[0]==28 THEN ZROT[0]=0 + ; YROT[1]=ZROT[0] + + inc ZROT_arr + lda ZROT_arr + cmp #28 + bne zrot_ok + lda #0 + sta ZROT_arr +zrot_ok: + sta YROT_arr+1 + + jsr CRUNCH + + jmp loop + + nop +.align $100 ; 400 + nop +.align $100 ; 500 + nop +.align $100 ; 600 + nop +.align $100 ; 700 + nop +.align $100 ; 700 + + +;=========================================================== +; If configured without the HRCG, the module starts here. * +;=========================================================== + +;=========================================================== +; Note that all tables are page-aligned for performance. * +;=========================================================== + +.include "shapes.s" + +; +; 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 + +.include "math_constants.s" + +.include "hgr_tables.s" + +.include "scale_constants.s" + +; +; 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 + +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 + lda #$0 + ldy #$F +_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). + + +CODE_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +X_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +Y_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +XROT_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +YROT_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +ZROT_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +SCALE_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +SX_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +SY_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + + + +.if 0 + +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 +.endif + + ; Junk; pads binary to end of page. +.align $0100 + diff --git a/graphics/hgr/budge3d/asm_example/zp.inc b/graphics/hgr/budge3d/asm_example/zp.inc new file mode 100644 index 00000000..83dfdf87 --- /dev/null +++ b/graphics/hgr/budge3d/asm_example/zp.inc @@ -0,0 +1,33 @@ +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) + +; 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 = $00 +FIRST_LINE = $45 +LAST_LINE = $46 diff --git a/graphics/hgr/budge3d/basic_example/Makefile b/graphics/hgr/budge3d/basic_example/Makefile new file mode 100644 index 00000000..892f8f41 --- /dev/null +++ b/graphics/hgr/budge3d/basic_example/Makefile @@ -0,0 +1,40 @@ +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 TEST SHIP_CUBE + cp $(EMPTY_DISK)/empty.dsk budge3d.dsk + $(DOS33) -y budge3d.dsk SAVE A HELLO + $(DOS33) -y budge3d.dsk SAVE A TEST + $(DOS33) -y budge3d.dsk BSAVE -a 0x300 SHIP_CUBE + + +### + +HELLO: hello.bas + $(TOKENIZE) < hello.bas > HELLO + +### + +TEST: test.bas + $(TOKENIZE) < test.bas > TEST + +#### + +SHIP_CUBE: ship_cube.o + ld65 -o SHIP_CUBE ship_cube.o -C $(LINKER_SCRIPTS)/apple2_300.inc + +ship_cube.o: ship_cube.s \ + zp.inc hardware.inc \ + shapes.s math_constants.s hgr_tables.s \ + hgr_textgen.s scale_constants.s + ca65 -o ship_cube.o ship_cube.s -l ship_cube.lst + +#### +clean: + rm -f *~ *.o *.lst HELLO SHIP_CUBE TEST diff --git a/graphics/hgr/budge3d/basic_example/hardware.inc b/graphics/hgr/budge3d/basic_example/hardware.inc new file mode 100644 index 00000000..269c4a3c --- /dev/null +++ b/graphics/hgr/budge3d/basic_example/hardware.inc @@ -0,0 +1,17 @@ +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 + diff --git a/graphics/hgr/budge3d/basic_example/hello.bas b/graphics/hgr/budge3d/basic_example/hello.bas new file mode 100644 index 00000000..8ef36c79 --- /dev/null +++ b/graphics/hgr/budge3d/basic_example/hello.bas @@ -0,0 +1,3 @@ +10 POKE 24576,0: POKE 103,1: POKE 104,96: POKE 175,1: POKE 176,96 +30 PRINT CHR$ (4)"RUN TEST" + diff --git a/graphics/hgr/budge3d/basic_example/hgr_tables.s b/graphics/hgr/budge3d/basic_example/hgr_tables.s new file mode 100644 index 00000000..3fa45f1d --- /dev/null +++ b/graphics/hgr/budge3d/basic_example/hgr_tables.s @@ -0,0 +1,102 @@ +; +; 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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $01,$02,$04,$08,$10,$20,$40,$01,$02,$04,$08,$10,$20,$40 + .byte $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) + diff --git a/graphics/hgr/budge3d/hgr_textgen.s b/graphics/hgr/budge3d/basic_example/hgr_textgen.s similarity index 100% rename from graphics/hgr/budge3d/hgr_textgen.s rename to graphics/hgr/budge3d/basic_example/hgr_textgen.s diff --git a/graphics/hgr/budge3d/basic_example/math_constants.s b/graphics/hgr/budge3d/basic_example/math_constants.s new file mode 100644 index 00000000..a0e38fa5 --- /dev/null +++ b/graphics/hgr/budge3d/basic_example/math_constants.s @@ -0,0 +1,68 @@ +; +; 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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $f0,$f0,$f2,$f3,$f6,$f9,$fc,$00,$04,$07,$0a,$0d,$0e,$10,$10,$00 + diff --git a/graphics/hgr/budge3d/basic_example/scale_constants.s b/graphics/hgr/budge3d/basic_example/scale_constants.s new file mode 100644 index 00000000..a6eafba1 --- /dev/null +++ b/graphics/hgr/budge3d/basic_example/scale_constants.s @@ -0,0 +1,113 @@ +; +; 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 + diff --git a/graphics/hgr/budge3d/basic_example/shapes.s b/graphics/hgr/budge3d/basic_example/shapes.s new file mode 100644 index 00000000..5968f815 --- /dev/null +++ b/graphics/hgr/budge3d/basic_example/shapes.s @@ -0,0 +1,208 @@ +;=========================================================== +; +; 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: + + ; spaceship + + .byte $c4,$c7,$c7,$c7,$c7,$d6,$d6,$d6 ; $00 + .byte $d6,$f1,$f1,$00,$00,$15,$15,$1e ; $08 + .byte $1e,$1e,$1e,$24,$24,$24,$24,$09 ; $10 + .byte $1b,$15,$1e ; $18 + + ; cube + .byte $fb,$05,$05,$fb,$fb ; $1b + .byte $05,$05,$fb ; $20 + + ; junk + + .byte $ec,$fc,$0c,$18,$28,$30,$44,$50,$74,$7c,$05,$fb,$00,$c4,$ca,$ca,$ca,$ca,$d6,$d6,$d6,$d6,$f1,$f1,$00,$00,$15,$15,$1e + .byte $1e,$1e,$1e,$24,$24,$24,$24,$09,$1b,$15,$1e,$d8,$e8,$f8,$08,$18,$28,$9c,$c4,$ec,$14,$3c,$64,$c9,$37,$b5,$4b,$22,$de,$de,$f2,$0e + .byte $22,$22,$de,$de,$f2,$0e,$22,$28,$39,$46,$d8,$c7,$ba,$00,$00,$00,$4d,$4d,$3f,$3f,$b3,$b3,$c1,$c1,$f9,$07,$07,$f9,$11,$ef,$ef,$11 + .byte $08,$f8,$0a,$f6,$19,$e7,$19,$e7,$00,$fa,$06,$00,$00,$fc,$04,$fc,$04,$fa,$06,$f6,$0a,$fc,$04,$f4,$0c,$fa,$06,$fa,$06,$f6,$0a,$f6 + .byte $0a,$f4,$0c,$f4,$0c,$d0,$30,$d0,$30,$d0,$30,$d0,$30,$d0,$30,$d0,$30,$d3,$06,$fc,$1a,$ba,$00,$da,$03,$16,$1a,$b0,$00,$ba,$02,$10 + .byte $34,$1a,$98,$19,$2b,$da,$03,$1b,$ab,$3b,$a0,$a0,$ab,$a4,$01,$df,$82,$d9,$0b,$f2,$0c,$d8,$06,$06,$2b,$7c,$10,$5b,$08,$3f,$19,$16 + .byte $0f,$01,$9c,$19,$23,$0f,$01,$97,$f2,$18,$24,$00,$0c,$c0,$f8,$06,$ed,$2b,$7c,$42,$1a,$ac,$00,$ba,$5c,$06,$f1,$1a,$03,$00,$da,$06 + +; 3D mesh Y coordinates (0, 3, ...) +ShapeYCoords: + ; spaceship + .byte $00,$03,$03,$fd,$fd,$06,$09,$fa + .byte $f7,$09,$f7,$0f,$f1,$24,$dc,$24 + .byte $dc,$09,$f7,$09,$f7,$06,$fa,$00 + .byte $00,$00,$00 + + ; cube + .byte $fb,$fb,$05,$05,$fb + .byte $fb,$05,$05 + + ; garbage + .byte $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: + ; spaceship + .byte $00,$03,$fd,$03,$fd,$09,$fa,$09 + .byte $fa,$fa,$fa,$fa,$fa,$fa,$fa,$fa + .byte $fa,$fa,$fa,$fa,$fa,$09,$09,$09 + .byte $09,$1b,$1b + + ; cube + .byte $fb,$fb,$fb,$fb,$05 + .byte $05,$05,$05 + + ; garbage + .byte $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 + ; spaceship (29 lines) + .byte $00,$00,$00,$00,$01,$02,$03,$04 + .byte $06,$08,$09,$0a,$0b,$0c,$0d,$0e + .byte $0f,$10,$11,$12,$13,$05,$07,$13 + .byte $14,$15,$17,$19,$1a + + ; cube (12 lines) + .byte $1b,$1c,$1d + .byte $1e,$1f,$20,$21,$22,$1b,$1c,$1d + .byte $1e + + ; junk + .byte $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 + + ; spaceship (29 lines) + .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 + + ; cube (12 lines) + .byte $1c,$1d,$1e + .byte $1b,$20,$21,$22,$1f,$1f,$20,$21 + .byte $22 + + ; junk + .byte $27,$28,$29,$2a,$2b,$2c,$2f,$2f,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f + .byte $40,$41,$42,$43,$44,$44,$45,$46,$45,$46,$46,$49,$4a,$4a,$51,$52,$53,$54,$55,$56,$50,$58,$5a,$56,$5e,$64,$63,$64,$60,$66,$65,$66 + .byte $67,$67,$68,$68,$69,$6a,$6a,$6b,$6b,$6c,$6d,$6d,$6e,$6e,$6f,$71,$72,$73,$70,$75,$76,$77,$74,$79,$7a,$7b,$78,$7d,$7e,$7f,$7c,$82 + .byte $83,$81,$80,$85,$84,$80,$81,$60,$5d,$84,$85,$89,$8a,$8b,$8d,$8e,$8f,$90,$91,$92,$93,$94,$95,$96,$97,$98,$9b,$9c,$99,$9a,$9a,$9b + .byte $9c,$9b,$9c,$a5,$a9,$ad,$a7,$ab,$af,$a6,$aa,$ae,$a8,$ac,$b0,$10,$dd,$08,$3f,$19,$6b,$0f,$00,$20,$d0,$09,$20,$0c,$fd,$c9,$d3,$66 + .byte $33,$20,$ce,$0a,$a9,$ff,$85,$2f,$d0,$00,$20,$61,$0c,$20,$89,$f6,$11,$00,$02,$29,$d4,$06,$04,$49,$51,$01,$f8,$4a,$06,$03,$51,$01 + .byte $fa,$21,$3a,$f2,$42,$51,$d3,$07,$fb,$19,$00,$02,$11,$7c,$03,$24,$71,$2a,$71,$00,$20,$7b,$0d,$24,$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 + .byte $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 + .byte $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 + .byte $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 + .byte $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 + .byte $10,$20,$30,$40,$50,$60,$70,$80 + .byte $90,$a0,$b0,$c0,$d0,$e0,$d0,$c0 + .byte $b0,$a0,$90,$80 + +RotIndexHi_sin: + .byte $07,$06,$05,$04,$03,$02,$01,$00 + .byte $01,$02,$03,$04,$05,$06,$07,$08 + .byte $09,$0a,$0b,$0c,$0d,$0e,$0d,$0c + .byte $0b,$0a,$09,$08 + +RotIndexLo_cos: + .byte $00,$10,$20,$30,$40,$50,$60,$70 + .byte $80,$90,$a0,$b0,$c0,$d0,$e0,$d0 + .byte $c0,$b0,$a0,$90,$80,$70,$60,$50 + .byte $40,$30,$20,$10 + +RotIndexHi_cos: + .byte $00,$01,$02,$03,$04,$05,$06,$07 + .byte $08,$09,$0a,$0b,$0c,$0d,$0e,$0d + .byte $0c,$0b,$0a,$09,$08,$07,$06,$05 + .byte $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) + diff --git a/graphics/hgr/budge3d/basic_example/ship_cube.s b/graphics/hgr/budge3d/basic_example/ship_cube.s new file mode 100644 index 00000000..1e65d97f --- /dev/null +++ b/graphics/hgr/budge3d/basic_example/ship_cube.s @@ -0,0 +1,1170 @@ +;============================================================================ +; 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. +;============================================================================ + +.include "zp.inc" + +.include "hardware.inc" + +; org $0300 + +.include "hgr_textgen.s" + +;=========================================================== +; If configured without the HRCG, the module starts here. * +;=========================================================== + +;=========================================================== +; Note that all tables are page-aligned for performance. * +;=========================================================== + +.include "shapes.s" + +; +; 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 + +.include "math_constants.s" + +.include "hgr_tables.s" + +.include "scale_constants.s" + +; +; 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 + +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/graphics/hgr/budge3d/test.bas b/graphics/hgr/budge3d/basic_example/test.bas similarity index 100% rename from graphics/hgr/budge3d/test.bas rename to graphics/hgr/budge3d/basic_example/test.bas diff --git a/graphics/hgr/budge3d/basic_example/zp.inc b/graphics/hgr/budge3d/basic_example/zp.inc new file mode 100644 index 00000000..83dfdf87 --- /dev/null +++ b/graphics/hgr/budge3d/basic_example/zp.inc @@ -0,0 +1,33 @@ +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) + +; 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 = $00 +FIRST_LINE = $45 +LAST_LINE = $46 diff --git a/graphics/hgr/budge3d/hardware.inc b/graphics/hgr/budge3d/hardware.inc index 269c4a3c..f64e4e33 100644 --- a/graphics/hgr/budge3d/hardware.inc +++ b/graphics/hgr/budge3d/hardware.inc @@ -1,13 +1,3 @@ -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 diff --git a/graphics/hgr/budge3d/hello.bas b/graphics/hgr/budge3d/hello.bas index 8ef36c79..fba2ddfb 100644 --- a/graphics/hgr/budge3d/hello.bas +++ b/graphics/hgr/budge3d/hello.bas @@ -1,3 +1,2 @@ -10 POKE 24576,0: POKE 103,1: POKE 104,96: POKE 175,1: POKE 176,96 -30 PRINT CHR$ (4)"RUN TEST" +10 PRINT CHR$ (4)"BRUN SHIP_CUBE" diff --git a/graphics/hgr/budge3d/ship_cube.s b/graphics/hgr/budge3d/ship_cube.s index 1e65d97f..fcca6fba 100644 --- a/graphics/hgr/budge3d/ship_cube.s +++ b/graphics/hgr/budge3d/ship_cube.s @@ -14,52 +14,47 @@ ; "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. -; +; simple cube 11 units on a side. The module is configured for XOR drawing + ; This makes extensive use of self-modifying code. Labels that begin with an ; underscore indicate self-modification targets. + +; Note from Vince Weaver +; + I've taken the disassembly and am converting it to assembly language +; I guess it might make more sense to get an assembly language kernel +; from the program, but I'm going to modify the BASIC anyway + + + ;=========================================================================== -; 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, +; CODE_arr+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. +; X_arr+N: X coordinate of center (0-255). +; Y_arr+N: Y coordinate of center (0-191). +; SCALE_arr+N: scale factor, 0-15. 15 is full size, 0 is 1/16th. +; XROT_arr+N: rotation about X axis, 0-27. 0 is no rotation, 27 is just shy +; of 360 degrees. +; YROT_arr+N: rotation about Y axis. +; ZROT_arr+N: rotation about Z axis. +; SX_arr+N: (output) X coordinate of last point drawn. +; SY_arr+N: (output) Y coordinate of last point drawn. ; ; The code entry points are: -; RESET%: initializes graphics module, clears the screen, switches display +; 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. +; CLR: clears both hi-res screens and switches to primary hi-res page. +; HIRES: turns on primary hi-res page. +; CRUNCH: 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. ;============================================================================ .include "zp.inc" @@ -68,7 +63,84 @@ ; org $0300 -.include "hgr_textgen.s" +entry: + jsr RESET + + ; CODE[0]=1 -> transform and draw + ; CODE[1]=1 -> transform and draw + + lda #1 + sta CODE_arr + sta CODE_arr+1 + + ; X[0]=127 Y[0]=96:X[1]=20:Y[1]=30 -> co-ord of center + + lda #127 + sta X_arr + lda #96 + sta Y_arr + + lda #20 + sta X_arr+1 + lda #30 + sta Y_arr+1 + + ; SCALE[0]=15:XROT[0]=2:YROT[0]=5:ZROT[0]=0 + ; SCALE[1]=15:XROT[1]=2:YROT[1]=5:ZROT[1]=0 + + lda #15 + sta SCALE_arr + sta SCALE_arr+1 + + lda #2 + sta XROT_arr + sta XROT_arr+1 + + lda #5 + sta YROT_arr + sta YROT_arr+1 + + lda #0 + sta ZROT_arr + sta ZROT_arr+1 + + jsr CRUNCH + jsr CRUNCH + + ; CODE[0]=2:CODE[1]=2 -> erase and draw new + + lda #2 + sta CODE_arr + sta CODE_arr+1 + +loop: + ; ZROT[0]+=1: IF ZEROT[0]==28 THEN ZROT[0]=0 + ; YROT[1]=ZROT[0] + + inc ZROT_arr + lda ZROT_arr + cmp #28 + bne zrot_ok + lda #0 + sta ZROT_arr +zrot_ok: + sta YROT_arr+1 + + jsr CRUNCH + + jmp loop + + nop +.align $100 ; 400 + nop +.align $100 ; 500 + nop +.align $100 ; 600 + nop +.align $100 ; 700 + nop +.align $100 ; 700 + ;=========================================================== ; If configured without the HRCG, the module starts here. * @@ -878,17 +950,17 @@ SavedShapeIndex: ;LAST_LINE = $46 CRUNCH: - jsr Setup ; 6 find Applesoft arrays +; jsr Setup ; 6 find Applesoft arrays ;============================== ; First pass: erase old shapes ;============================== lda NumObjects ; 4 number of defined objects - asl ; 2 * 2 +; asl ; 2 * 2 tax ; 2 use as index ShapeLoop: - dex ; 2 +; dex ; 2 dex ; 2 bmi Transform ; 2+ done _codeAR1: @@ -896,9 +968,9 @@ _codeAR1: cmp #$02 ; 2 2 or 3? bcc ShapeLoop ; 2+ no, move on stx SavedShapeIndex ; 4 - txa ; 2 - lsr ; 2 - tax ; 2 +; txa ; 2 +; lsr ; 2 +; tax ; 2 lda FirstLineIndex,X; 4+ sta FIRST_LINE ; 3 lda LastLineIndex,X ; 4+ @@ -916,10 +988,10 @@ NoLines1: ;=============================== Transform: lda NumObjects ; 4 - asl ; 2 +; asl ; 2 tax ; 2 TransLoop: - dex ; 2 +; dex ; 2 dex ; 2 bmi DrawNew ; 2+ _codeAR2: @@ -950,9 +1022,9 @@ _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 +; 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+ @@ -981,10 +1053,10 @@ _syAR: DrawNew: lda NumObjects ; 4 - asl ; 2 +; asl ; 2 tax ; 2 L1ECE: - dex ; 2 +; dex ; 2 dex ; 2 bmi L1EF9 ; 2+ _codeAR3: @@ -993,9 +1065,9 @@ _codeAR3: 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 +; 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+ @@ -1020,7 +1092,9 @@ L1EF9: ;******************************************************************************* RESET: - jsr Setup ; 6 sets A=0, Y=$1E +; jsr Setup ; 6 sets A=0, Y=$1E + lda #$0 + ldy #$F _codeAR4: sta CODE_arr,y ; 5 zero out CODE% dey ; 2 @@ -1082,6 +1156,30 @@ HI_RES: ; If you generate the module for Integer BASIC, this is the entry point for ; MISSILE (7993). + +CODE_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +X_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +Y_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +XROT_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +YROT_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +ZROT_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +SCALE_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +SX_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 +SY_arr: + .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + + + +.if 0 + Setup: lda BAS_ARYTAB ; 3 CODE% is at +$0008 clc ; 2 @@ -1164,6 +1262,7 @@ Setup: ldy #$1e ; 2 Set A and Y for RESET lda #$00 ; 2 rts ; 6 +.endif ; Junk; pads binary to end of page. .align $0100