diff --git a/graphics/gr/raycast/Makefile b/graphics/gr/raycast/Makefile index bf82af12..40801bde 100644 --- a/graphics/gr/raycast/Makefile +++ b/graphics/gr/raycast/Makefile @@ -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 diff --git a/graphics/gr/raycast/ray.bas b/graphics/gr/raycast/ray.bas index c195ca7d..416fb7c1 100644 --- a/graphics/gr/raycast/ray.bas +++ b/graphics/gr/raycast/ray.bas @@ -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 diff --git a/graphics/gr/raycast/ray_good.bas b/graphics/gr/raycast/ray_good.bas new file mode 100644 index 00000000..d16244a4 --- /dev/null +++ b/graphics/gr/raycast/ray_good.bas @@ -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 diff --git a/graphics/gr/raycast/ray_more.bas b/graphics/gr/raycast/ray_more.bas new file mode 100644 index 00000000..3ceba41f --- /dev/null +++ b/graphics/gr/raycast/ray_more.bas @@ -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 diff --git a/graphics/gr/raycast/raycast.s b/graphics/gr/raycast/raycast.s index 20c651d2..b0f3799e 100644 --- a/graphics/gr/raycast/raycast.s +++ b/graphics/gr/raycast/raycast.s @@ -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 diff --git a/graphics/gr/raycast/raymarch.s b/graphics/gr/raycast/raymarch.s new file mode 100644 index 00000000..998464c9 --- /dev/null +++ b/graphics/gr/raycast/raymarch.s @@ -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 # 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 + diff --git a/graphics/gr/raycast/raymarch_tiny.s b/graphics/gr/raycast/raymarch_tiny.s new file mode 100644 index 00000000..cf2e879a --- /dev/null +++ b/graphics/gr/raycast/raymarch_tiny.s @@ -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 # 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 +;---------------------------------------