raycast: more hacking

This commit is contained in:
Vince Weaver 2021-06-02 17:03:37 -04:00
parent ca7c9dcfb9
commit 1bf6734efa
7 changed files with 1155 additions and 54 deletions

View File

@ -12,10 +12,14 @@ all: raycast.dsk
$(DOS33):
cd ../../utils/dos33fs-utils && make
raycast.dsk: $(DOS33) HELLO RAYCAST
raycast.dsk: $(DOS33) HELLO RAYCAST RAYMARCH RAYMARCH_TINY RAY.BAS
cp $(EMPTYDISK)/empty.dsk raycast.dsk
$(DOS33) -y raycast.dsk SAVE A HELLO
$(DOS33) -y raycast.dsk SAVE A RAY.BAS
$(DOS33) -y raycast.dsk BSAVE -a 0xc00 RAYCAST
$(DOS33) -y raycast.dsk BSAVE -a 0xc00 RAYMARCH
$(DOS33) -y raycast.dsk BSAVE -a 0xc00 RAYMARCH_TINY
###
@ -25,15 +29,39 @@ HELLO: hello.bas
###
RAY.BAS: ray.bas
$(TOKENIZE) < ray.bas > RAY.BAS
###
RAYCAST: raycast.o
ld65 -o RAYCAST raycast.o -C $(LINKERSCRIPTS)/apple2_c00.inc
raycast.o: raycast.s
ca65 -o raycast.o raycast.s -l raycast.lst
###
RAYMARCH: raymarch.o
ld65 -o RAYMARCH raymarch.o -C $(LINKERSCRIPTS)/apple2_c00.inc
raymarch.o: raymarch.s
ca65 -o raymarch.o raymarch.s -l raymarch.lst
###
RAYMARCH_TINY: raymarch_tiny.o
ld65 -o RAYMARCH_TINY raymarch_tiny.o -C $(LINKERSCRIPTS)/apple2_c00.inc
raymarch_tiny.o: raymarch_tiny.s
ca65 -o raymarch_tiny.o raymarch_tiny.s -l raymarch_tiny.lst
###
clean:
rm -f *~ *.o HELLO RAYCAST *.lst
rm -f *~ *.o HELLO RAYCAST RAYMARCH RAYMARCH_TINY *.lst

View File

@ -1,13 +1,7 @@
10 GR
20 FOR Y=0 TO 39:Z=Y*0.04
30 A=Z+H:XX=SIN(A)/2:YY=COS(A)/2:D=0:RX=PX:RY=PY
40 D=D+1:IF D>40 THEN 60
50 RX=RX+XX:RY=RY+YY
55 C=0:IF ABS(RX)>16 OR ABS(RY)>16 THEN C=5
56 IF RX>4 AND RX<6 AND RY>4 AND RY<6 THEN C=1
57 IF C=0 THEN 40
60 U=40/D:IF U>19 THEN U=19
70 V=19-U:COLOR=7:VLIN0,V AT Y
75 COLOR=C:VLINV,V+U+U AT Y
80 COLOR=8:VLIN V+U+U,39 AT Y
100 NEXT Y:H=H+0.2:GOTO 20
0GR
1Z=H:FORI=0TO39:Z=Z+.04:X=SIN(Z)/2:Y=COS(Z)/2:D=0:R=P:S=Q
2D=D+1:R=R+X:S=S+Y:C=0:A=ABS(R):B=ABS(S):IFA>6ORB>6THENC=5
5IFA>3ANDA<5ANDB>3ANDB<5THENC=1
6IFC=0THEN2
7U=40/D:IFU>19THENU=19
8V=19-U:U=19+U:COLOR=7:VLIN0,VATI:COLOR=C:VLINV,UATI:COLOR=8:VLINU,39ATI:NEXT:H=H+.2:GOTO1

View File

@ -0,0 +1,13 @@
10 GR
20 Z=H:FOR Y=0 TO 39:Z=Z+0.04
30 XX=SIN(Z)/2:YY=COS(Z)/2:D=0:RX=PX:RY=PY
40 D=D+1:IF D>40 THEN 60
50 RX=RX+XX:RY=RY+YY
55 C=0:IF ABS(RX)>16 OR ABS(RY)>16 THEN C=5
56 IF RX>4 AND RX<6 AND RY>4 AND RY<6 THEN C=1
57 IF C=0 THEN 40
60 U=40/D:IF U>19 THEN U=19
70 V=19-U:COLOR=7:VLIN0,V AT Y
75 COLOR=C:VLINV,V+U+U AT Y
80 COLOR=8:VLIN V+U+U,39 AT Y
100 NEXT Y:H=H+0.2:GOTO 20

View File

@ -0,0 +1,8 @@
0GR
1Z=H:FORI=0TO39:Z=Z+.04:X=SIN(Z)/2:Y=COS(Z)/2:D=0:R=P:S=Q
2D=D+1:R=R+X:S=S+Y:C=0:A=ABS(R):B=ABS(S):IFA>8ORB>8THENC=5
5IFA>4ANDA<6ANDB>4ANDB<6THENC=1
6IFC=0ANDD<40THEN2
7U=40/D:IFU>19THENU=19
8V=19-U:U=19+U:COLOR=7:VLIN0,VATI:COLOR=C:VLINV,UATI:COLOR=8:VLINU,39ATI
9NEXT:H=H+.2:GOTO1

View File

@ -1,7 +1,8 @@
;---------------------------------------
; based on 1bir - 1 block interactive raycaster
; coded by huseyin kilic (wisdom)
; copyright (c) 2009-2013 crescent
; based on 1bir - 1 block interactive raycaster for Commodore 64
; coded by huseyin kilic (wisdom) copyright (c) 2009-2013 crescent
;
; converted to Apple II by Vince `deater` Weaver
.include "hardware.inc"
@ -23,7 +24,8 @@ PLAYERXH = $6a
PLAYERY = $6b
PLAYERYH = $6c
DISTANCE = $70 ; reset in $bc00 and $bc0f calls
DISTANCE = $70
NEWLOC = $71
ROWPTR = $d1
ROWPTRH = $d2
@ -37,8 +39,6 @@ HEADING = $81
SINADD = $9a
COLORS = $b1 ; 3 bytes consecutively
; temp
CURRENTROW = $ff
; constants
sin_t = $1000
@ -70,7 +70,7 @@ gensin_loop:
sta sin_t,Y
iny
clc
] adc SINADD
adc SINADD
ldx SINADD
dec sincount_t,X
bne gensin_loop
@ -125,11 +125,10 @@ loop_ray:
; distance is reset on return from this call
jsr getsincos_copyplr2ray
; reset line row before each column gets drawn
; (needed in vertical line section)
; X is 0 here?
stx CURRENTROW
stx DISTANCE
loop_dist:
@ -209,7 +208,8 @@ vline_loop:
; vline sky, 0 to FLOOR_SKY_HEIGHT
; load color
lda #$77 ; sky blue
;lda #$77 ; sky blue
lda #$00 ; sky black
sta COLOR
lda FLOOR_SKY_HEIGHT
@ -315,21 +315,40 @@ done_user_input:
; for x and y components and also because of
; brute force approach
addsteptopos:
ldx #$0
stx NEWLOC
ldx #$02
loop_stepadd:
lda STEPX,X ; & y
ora #$7f ; sign extend 8 bit step value to 16 bit
bmi was_neg ; was negative *+4
bmi was_neg ; was negative
lda #$00
was_neg:
pha
;clc
lda STEPX,x ; & y
adc RAYPOSX,x ; & y
sta RAYPOSX,x ; & y
lda STEPX,X ; & y
adc RAYPOSX,X ; & y
sta RAYPOSX,X ; & y
pla
adc RAYPOSXH,x ; & y
sta RAYPOSXH,x ; & y
php
bcc blah ; no carry
cpx #2
bne blah
stx NEWLOC
blah:
plp
adc RAYPOSXH,X ; & y
sta RAYPOSXH,X ; & y
dex
dex
bpl loop_stepadd
@ -346,11 +365,20 @@ was_neg:
asl
asl
; by doing ora instead of adc, it is possible to have
; a closed area map in $ecb9
adc RAYPOSYH
tax
lda map_t,X
beq step_exit
ldx NEWLOC
cpx #2
bne step_exit
sec
sbc #$88
step_exit:
rts
@ -368,15 +396,16 @@ getsincos_copyplr2ray:
; copy player position to ray position for a start
; through the basic rom
copyplr2ray: ; $bc00 in c64 kernel?
ldx #$05 ; copy 5 bytes, from 69..6D to 61..65
; copy 4 bytes, from 69,6A,6B,6C to 61,62,63,64
copyplr2ray:
ldx #$04
copyloop:
lda $68,X
sta $60,X
dex
bne copyloop
stx DISTANCE ; side effect, needed?
rts
@ -407,17 +436,18 @@ stepandcopy:
; yes, move player by
; copying ray position to player position
; through the basic rom
copyray2plr: ; BC0f in c64 ROM
copyray2plr:
ldx #$6
; Copy 61,62,63,64 to 69,6A,6B,6C
ldx #$4
r2_loop:
lda $60,X
sta $68,X
dex
bne r2_loop
stx DISTANCE
rts
;---------------------------------------
@ -446,19 +476,19 @@ map_t:
map_t:
.byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
.byte $55,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$11,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$22,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$22,$22,$22,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$22,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$00,$00,$00,$00,$33,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$99,$99,$11,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$55
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$99,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$CC,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$CC,$CC,$CC,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$CC,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$99,$99,$11,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$EE,$00,$DD,$00,$CC,$00,$BB,$00,$AA,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff

View File

@ -0,0 +1,529 @@
;---------------------------------------
; based on 1bir - 1 block interactive raycaster for Commodore 64
; coded by huseyin kilic (wisdom) copyright (c) 2009-2013 crescent
;
; converted to Apple II by Vince `deater` Weaver
.include "hardware.inc"
; zero page
V2 = $2D
COLOR = $30
RAYPOSX = $61
RAYPOSXH = $62
RAYPOSY = $63
RAYPOSYH = $64
STEPX = $66 ; leave 1 byte between x and y
STEPY = $68
PLAYERX = $69
PLAYERXH = $6a
PLAYERY = $6b
PLAYERYH = $6c
DISTANCEL = $6F
DISTANCE = $70
NEWLOC = $71
HEIGHT = $73
HEIGHTL = $74
ROWPTR = $d1
ROWPTRH = $d2
LINEH_T = $d9
WALL_HEIGHT = $f8
FLOOR_SKY_HEIGHT= $f9
; external value dependencies
HEADING = $81
SINADD = $9a
COLORS = $b1 ; 3 bytes consecutively
; constants
sin_t = $1000
blocksize = $28
;---------------------------------------
; main
;---------------------------------------
main:
jsr SETGR
bit FULLGR
lda #$20
sta HEADING
;---------------------------------------
; sin/cos table generator
;---------------------------------------
; first generate sine for 0..63 (0..90 degrees)
lda #3
sta SINADD
lda #$00
tay
gensin_loop:
sta sin_t,Y
iny
clc
adc SINADD
ldx SINADD
dec sincount_t,X
bne gensin_loop
dec SINADD
bpl gensin_loop
; x = $00
; y = $40
; next generate
gensin_loop2:
lda sin_t,X
sta sin_t+$0100,X ; copy at $100 so cosine easier
sta sin_t-1+$40,Y ; store 90-180 degrees
eor #$ff ; invert
sta sin_t+$80,X ; store for 180-270 degrees
sta sin_t-1+$c0,Y ; store for 270-360 degrees
inx
dey
bpl gensin_loop2
;---------------------------------------
; raycaster
;---------------------------------------
loop_main:
; cast 40 rays for each screen column
; starting with rightmost one
; Y is used as global column index
; throughout the rest of the program
ldy #39
loop_ray:
; determine current ray's direction
; by taking player's current direction
; and fov into account
; fov is 40 b-rads out of 256 b-rads
tya
clc
adc HEADING
;sec
sbc #19+1 ; half of the fov (+1 because of sec)
tax
; get sin/cos values accordingly
; and copy player position to current ray position
; distance is reset on return from this call
jsr getsincos_copyplr2ray
; reset line row before each column gets drawn
; (needed in vertical line section)
; X is 0 here?
stx DISTANCEL
stx DISTANCE
loop_dist:
; step along current ray's path and find distance
clc
lda DISTANCEL
adc #$80
sta DISTANCEL
bcc nod
inc DISTANCE
nod:
; limit distance when it is needed in larger maps
; or open (wrapped) maps
; max distance = $29
; lda DISTANCE
; cmp #$29
; bcs skip_dist
; max distance = $40 (make sure ar is always 0 here)
; bit DISTANCE
; bvs skip_dist
; max DISTANCE = $80
lda DISTANCE
bmi skip_dist
jsr addsteptopos
; on return from last call, A is cell (block) value
; A == 0 means empty cell, so continue tracing
beq loop_dist
skip_dist:
; now A contains the value in reached map position
; (or last cell value fetched if max distance is reached)
; use A or X to colorize the block
; and #$07
; ora #$03
sta COLORS+1
; find out visible block height
; according to distance
ldx #$ff
; calculate visible block height through simple division
lda #0
sta HEIGHT
sta HEIGHTL
height_loop:
inx
lda HEIGHTL
adc DISTANCEL
sta HEIGHTL
lda HEIGHT
adc DISTANCE
sta HEIGHT
cmp #<blocksize
bcc height_loop
dex
; lda #<blocksize
;loop_div:
; inx
; ; sec
; sbc DISTANCE
; bcs loop_div
; X = half of visible block height
txa
;---------------------------------------
; vertical line
;---------------------------------------
; Y = x position (screen column)
; A = half height (zero height is ok)
cmp #24 ; height > 24?
bcc vline_validheight
lda #23 ; make sure max height = 24
vline_validheight:
asl ; calculate full height
sta WALL_HEIGHT ; store for looping below
eor #$ff ; subtract full height from screen height
; sec ; (48 rows)
adc #48+1 ; +1 because of sec
lsr ; sky/floor heights are equal to each other
sta FLOOR_SKY_HEIGHT
; loop through 3 sections of one screen column
; i.e. sky - wall - floor
vline_loop:
;==========
; vline sky, 0 to FLOOR_SKY_HEIGHT
; load color
;lda #$77 ; sky blue
lda #$00 ; sky black
sta COLOR
lda FLOOR_SKY_HEIGHT
sta V2
lda #0
jsr VLINE ; VLINE A,$2D at Y (Y preserved, A=V2)
;=================
; vline wall, FLOOR_SKY_HEIGHT to FLOOR_SKY_HEIGHT+WALL_HEIGHT
ldx COLORS+1
stx COLOR
; A already FLOOR_SKY_HEIGHT
clc
adc WALL_HEIGHT
sta V2
lda FLOOR_SKY_HEIGHT
jsr VLINE ; VLINE A,$2D at Y
;=============
; vline floor, WALL_HEIGHT+FLOOR_SKY_HEIGHT to 47
ldx #$88
stx COLOR
; A already WALL_HEIGHT+FLOOR_SKY_HEIGHT
ldx #47
stx V2
jsr VLINE ; VLINE A,$2D at Y
;---------------------------------------
; advance to next ray/column
dey
bpl loop_ray
;---------------------------------------
; user input
;---------------------------------------
; common preparation code to set up sin/cos and
; to copy player position to ray position to trace movement
; direction to determine if player hits a block
; in case player actually tries to move forward or backwards
ldx HEADING
jsr getsincos_copyplr2ray
; get joystick 2 status (lowest 4 bits)
; and check each bit to determine action
lda KEYPRESS
beq done_user_input
cmp #'W'+$80
bne skip_j1
; try to move forward
pha
jsr stepandcopy
pla
skip_j1:
cmp #'S'+$80
bne skip_j2
; try to move backward
pha
jsr invertstepandcopy
pla
skip_j2:
cmp #'A'+$80
bne skip_j3
; turn right
dec HEADING
dec HEADING
skip_j3:
cmp #'D'+$80
bne done_user_input
; turn left
inc HEADING
inc HEADING
done_user_input:
bit KEYRESET ; clear keyboard buffer
; absolute jump, as carry is always 0 here
jmp loop_main
;---------------------------------------
; ray tracing subroutines
;---------------------------------------
; heart of tracing, very slow, because of looping
; for x and y components and also because of
; brute force approach
addsteptopos:
ldx #$0
stx NEWLOC
ldx #$02
loop_stepadd:
lda STEPX,X ; & y
ora #$7f ; sign extend 8 bit step value to 16 bit
bmi was_neg ; was negative
lda #$00
was_neg:
pha
;clc
lda STEPX,X ; & y
adc RAYPOSX,X ; & y
sta RAYPOSX,X ; & y
pla
php
bcc blah ; no carry
cpx #2
bne blah
stx NEWLOC
blah:
plp
adc RAYPOSXH,X ; & y
sta RAYPOSXH,X ; & y
dex
dex
bpl loop_stepadd
; A = RAYPOSXH
; calculate index to look up the map cell
; the map area is 8x8 bytes
; + instead of the usual y * 8 + x
; x * 8 + y done here, to save some bytes
; (just causing a flip of the map as a side effect)
asl
asl
asl
asl
adc RAYPOSYH
tax
lda map_t,X
beq step_exit
ldx NEWLOC
cpx #2
bne step_exit
sec
sbc #$88
step_exit:
rts
;---------------------------------------
; getsincos_copyplr2ray
;---------------------------------------
getsincos_copyplr2ray:
lda sin_t,X ; sin(x)
cmp #$80
ror
sta STEPX
lda sin_t+$40,X ; cos(x)
cmp #$80
ror
sta STEPY
; copy player position to ray position for a start
; through the basic rom
; copy 4 bytes, from 69,6A,6B,6C to 61,62,63,64
copyplr2ray:
ldx #$04
copyloop:
lda $68,X
sta $60,X
dex
bne copyloop
rts
;======================================
; invert step and copy
;======================================
invertstepandcopy:
; invert step variables for backward motion
invertstepx: ; from BFB8 in C64 ROM
lda $66
eor #$ff
sta $66
invertstepy:
lda STEPY
eor #$ff
sta STEPY
;=======================================
; stepandcopy
;=======================================
stepandcopy:
; see if player can move to the direction desired
jsr addsteptopos
bne step_exit ; no, return without doing anything
; yes, move player by
; copying ray position to player position
copyray2plr:
; Copy 61,62,63,64 to 69,6A,6B,6C
ldx #$4
r2_loop:
lda $60,X
sta $68,X
dex
bne r2_loop
rts
;---------------------------------------
; data
;---------------------------------------
; number of sin additions (backwards)
sincount_t:
.byte 6,14,19,25
;---------------------------------------
.if 0
map_t:
.byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
.byte $55,$00,$00,$00,$00,$00,$00,$55
.byte $55,$00,$44,$00,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$11,$00,$55
.byte $55,$22,$00,$00,$00,$00,$00,$55
.byte $55,$00,$00,$99,$00,$00,$00,$55
.byte $55,$00,$00,$00,$00,$00,$00,$55
.byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
.endif
map_t:
.byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$99,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$CC,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$CC,$CC,$CC,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$CC,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$00,$EE,$00,$DD,$00,$CC,$00,$BB,$00,$AA,$00,$99,$00,$00,$ff
.byte $ff,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$ff
.byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff

View File

@ -0,0 +1,499 @@
;---------------------------------------
; based on 1bir - 1 block interactive raycaster for Commodore 64
; coded by huseyin kilic (wisdom) copyright (c) 2009-2013 crescent
;
; converted to Apple II by Vince `deater` Weaver
.include "hardware.inc"
; zero page
V2 = $2D
COLOR = $30
RAYPOSX = $61
RAYPOSXH = $62
RAYPOSY = $63
RAYPOSYH = $64
STEPX = $66 ; leave 1 byte between x and y
STEPY = $68
PLAYERX = $69
PLAYERXH = $6a
PLAYERY = $6b
PLAYERYH = $6c
DISTANCEL = $6F
DISTANCE = $70
NEWLOC = $71
HEIGHT = $73
HEIGHTL = $74
ROWPTR = $d1
ROWPTRH = $d2
LINEH_T = $d9
WALL_HEIGHT = $f8
FLOOR_SKY_HEIGHT= $f9
; external value dependencies
HEADING = $81
SINADD = $9a
COLORS = $b1 ; 3 bytes consecutively
; constants
sin_t = $1000
blocksize = $28
;---------------------------------------
; main
;---------------------------------------
main:
jsr SETGR
bit FULLGR
lda #$20
sta HEADING
;---------------------------------------
; sin/cos table generator
;---------------------------------------
; first generate sine for 0..63 (0..90 degrees)
lda #3
sta SINADD
lda #$00
tay
gensin_loop:
sta sin_t,Y
iny
clc
adc SINADD
ldx SINADD
dec sincount_t,X
bne gensin_loop
dec SINADD
bpl gensin_loop
; x = $00
; y = $40
; next generate
gensin_loop2:
lda sin_t,X
sta sin_t+$0100,X ; copy at $100 so cosine easier
sta sin_t-1+$40,Y ; store 90-180 degrees
eor #$ff ; invert
sta sin_t+$80,X ; store for 180-270 degrees
sta sin_t-1+$c0,Y ; store for 270-360 degrees
inx
dey
bpl gensin_loop2
;---------------------------------------
; raycaster
;---------------------------------------
loop_main:
; cast 40 rays for each screen column
; starting with rightmost one
; Y is used as global column index
; throughout the rest of the program
ldy #39
loop_ray:
; determine current ray's direction
; by taking player's current direction
; and fov into account
; fov is 40 b-rads out of 256 b-rads
tya
clc
adc HEADING
;sec
sbc #19+1 ; half of the fov (+1 because of sec)
tax
; get sin/cos values accordingly
; and copy player position to current ray position
; distance is reset on return from this call
jsr getsincos_copyplr2ray
; reset line row before each column gets drawn
; (needed in vertical line section)
; X is 0 here?
stx DISTANCEL
stx DISTANCE
loop_dist:
; step along current ray's path and find distance
clc
lda DISTANCEL
adc #$80
sta DISTANCEL
bcc nod
inc DISTANCE
nod:
; limit distance when it is needed in larger maps
; or open (wrapped) maps
; max distance = $29
lda DISTANCE
cmp #$29
bcs skip_dist
; max distance = $40 (make sure ar is always 0 here)
; bit DISTANCE
; bvs skip_dist
; max DISTANCE = $80
; lda DISTANCE
; bmi skip_dist
jsr addsteptopos
; on return from last call, A is cell (block) value
; A == 0 means empty cell, so continue tracing
beq loop_dist
skip_dist:
; now A contains the value in reached map position
; (or last cell value fetched if max distance is reached)
; use A or X to colorize the block
; and #$07
; ora #$03
sta COLORS+1
; find out visible block height
; according to distance
ldx #$ff
; calculate visible block height through simple division
lda #0
sta HEIGHT
sta HEIGHTL
height_loop:
inx
lda HEIGHTL
adc DISTANCEL
sta HEIGHTL
lda HEIGHT
adc DISTANCE
sta HEIGHT
cmp #<blocksize
bcc height_loop
;dex
; lda #<blocksize
;loop_div:
; inx
; ; sec
; sbc DISTANCE
; bcs loop_div
; X = half of visible block height
txa
;---------------------------------------
; vertical line
;---------------------------------------
; Y = x position (screen column)
; A = half height (zero height is ok)
cmp #24 ; height > 24?
bcc vline_validheight
lda #23 ; make sure max height = 24
vline_validheight:
asl ; calculate full height
sta WALL_HEIGHT ; store for looping below
eor #$ff ; subtract full height from screen height
; sec ; (48 rows)
adc #48+1 ; +1 because of sec
lsr ; sky/floor heights are equal to each other
sta FLOOR_SKY_HEIGHT
; loop through 3 sections of one screen column
; i.e. sky - wall - floor
vline_loop:
;==========
; vline sky, 0 to FLOOR_SKY_HEIGHT
; load color
;lda #$77 ; sky blue
lda #$00 ; sky black
sta COLOR
lda FLOOR_SKY_HEIGHT
sta V2
lda #0
jsr VLINE ; VLINE A,$2D at Y (Y preserved, A=V2)
;=================
; vline wall, FLOOR_SKY_HEIGHT to FLOOR_SKY_HEIGHT+WALL_HEIGHT
ldx COLORS+1
stx COLOR
; A already FLOOR_SKY_HEIGHT
clc
adc WALL_HEIGHT
sta V2
lda FLOOR_SKY_HEIGHT
jsr VLINE ; VLINE A,$2D at Y
;=============
; vline floor, WALL_HEIGHT+FLOOR_SKY_HEIGHT to 47
ldx #$88
stx COLOR
; A already WALL_HEIGHT+FLOOR_SKY_HEIGHT
ldx #47
stx V2
jsr VLINE ; VLINE A,$2D at Y
;---------------------------------------
; advance to next ray/column
dey
bpl loop_ray
;---------------------------------------
; user input
;---------------------------------------
; common preparation code to set up sin/cos and
; to copy player position to ray position to trace movement
; direction to determine if player hits a block
; in case player actually tries to move forward or backwards
ldx HEADING
jsr getsincos_copyplr2ray
; get joystick 2 status (lowest 4 bits)
; and check each bit to determine action
lda KEYPRESS
beq done_user_input
cmp #'W'+$80
bne skip_j1
; try to move forward
pha
jsr stepandcopy
pla
skip_j1:
cmp #'S'+$80
bne skip_j2
; try to move backward
pha
jsr invertstepandcopy
pla
skip_j2:
cmp #'A'+$80
bne skip_j3
; turn right
dec HEADING
dec HEADING
skip_j3:
cmp #'D'+$80
bne done_user_input
; turn left
inc HEADING
inc HEADING
done_user_input:
bit KEYRESET ; clear keyboard buffer
; absolute jump, as carry is always 0 here
jmp loop_main
;---------------------------------------
; ray tracing subroutines
;---------------------------------------
; heart of tracing, very slow, because of looping
; for x and y components and also because of
; brute force approach
addsteptopos:
ldx #$0
stx NEWLOC
ldx #$02
loop_stepadd:
lda STEPX,X ; & y
ora #$7f ; sign extend 8 bit step value to 16 bit
bmi was_neg ; was negative
lda #$00
was_neg:
pha
;clc
lda STEPX,X ; & y
adc RAYPOSX,X ; & y
sta RAYPOSX,X ; & y
pla
php
bcc blah ; no carry
cpx #2
bne blah
stx NEWLOC
blah:
plp
adc RAYPOSXH,X ; & y
sta RAYPOSXH,X ; & y
dex
dex
bpl loop_stepadd
; A = RAYPOSXH
; calculate index to look up the map cell
; the map area is 8x8 bytes
; + instead of the usual y * 8 + x
; x * 8 + y done here, to save some bytes
; (just causing a flip of the map as a side effect)
and RAYPOSYH ; sierpinski
and #$f0
beq step_exit
lda #$CC
; jmp blargh
;make_zero:
; lda #$00
; beq step_exit
;blargh:
ldx NEWLOC
cpx #2
bne step_exit
sec
sbc #$88
step_exit:
rts
;---------------------------------------
; getsincos_copyplr2ray
;---------------------------------------
getsincos_copyplr2ray:
lda sin_t,X ; sin(x)
cmp #$80
ror
sta STEPX
lda sin_t+$40,X ; cos(x)
cmp #$80
ror
sta STEPY
; copy player position to ray position for a start
; through the basic rom
; copy 4 bytes, from 69,6A,6B,6C to 61,62,63,64
copyplr2ray:
ldx #$04
copyloop:
lda $68,X
sta $60,X
dex
bne copyloop
rts
;======================================
; invert step and copy
;======================================
invertstepandcopy:
; invert step variables for backward motion
invertstepx: ; from BFB8 in C64 ROM
lda $66
eor #$ff
sta $66
invertstepy:
lda STEPY
eor #$ff
sta STEPY
;=======================================
; stepandcopy
;=======================================
stepandcopy:
; see if player can move to the direction desired
jsr addsteptopos
bne step_exit ; no, return without doing anything
; yes, move player by
; copying ray position to player position
copyray2plr:
; Copy 61,62,63,64 to 69,6A,6B,6C
ldx #$4
r2_loop:
lda $60,X
sta $68,X
dex
bne r2_loop
rts
;---------------------------------------
; data
;---------------------------------------
; number of sin additions (backwards)
sincount_t:
.byte 6,14,19,25
;---------------------------------------