Trevor Merritt e29ac45c84 scroll down works on CHIP-8 and High-Res modes
scroll left and right work in stdef and hidef
adds octo test roms
adds schip fonts to memory
2024-10-27 11:41:25 -04:00

311 lines
6.3 KiB
Plaintext

###########################################
#
# Chipenstein 3D
#
# A work-in-progress experiment
# in creating a raycast 2.5d shooter.
# Uses PWM techniques to simulate extra
# colors and must run at 1000 cycles/frame.
# Epilepsy warning!
#
###########################################
# The largest a map for this approach could be is 16x16.
# Technically we don't have to surround all sides with
# walls due to wraparound, but if there is a ray path
# around the map without hitting a wall our raycast
# routine will get stuck in an infinite loop:
: map-data
0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01
0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF
0xFF 0xFF 0x01 0xFF 0x00 0x00 0x00 0x00 0x00 0x01
0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF
0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
0x01 0x00 0xFF 0x01 0x00 0x00 0x00 0xFF 0x00 0xFF
0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF
: collision-test
# take whole x/y in vc/vd, return map color in v0
i := map-data
vF := 0b111
vc &= vF
i += vc # + (x % 8)
vd &= vF
v0 <<= vd
v0 <<= v0
v0 <<= v0
i += v0 # + (y % 8)*8
load v0 # the current map color
;
: player-position
0 0 0 0 # scratchpad
: save-position
v0 := va
v1 := vb
v2 := vc
v3 := vd
i := player-position
save v3
;
: restore-position
i := player-position
load v3
va := v0
vb := v1
vc := v2
vd := v3
;
###########################################
#
# Raycasting
#
###########################################
# This is a table of the deltas and magnitudes for a fixed-point representation
# of a cosine function. 64 entries correspond to ~5.6 degrees each.
# deltas are interleaved with magnitudes- 0 for positive and 1 for negative.
# deltas are normalized to slightly over half a step to make the distance calculations
# come up with a maximum distance of roughly 15. Generated like so:
#
# for(int x = 0; x < 64; x++) {
# double s = Math.cos(Math.PI*2/64*x);
# System.out.format("0x%02X 0x%02X ", (int)(140 * Math.abs(s)), (s>=0) ?0 : 1);
# if (x % 8 == 7) { System.out.println(); }
# }
: cosine-table
0x8C 0x00 0x8B 0x00 0x89 0x00 0x85 0x00 0x81 0x00 0x7B 0x00 0x74 0x00 0x6C 0x00
0x62 0x00 0x58 0x00 0x4D 0x00 0x41 0x00 0x35 0x00 0x28 0x00 0x1B 0x00 0x0D 0x00
0x00 0x00 0x0D 0x01 0x1B 0x01 0x28 0x01 0x35 0x01 0x41 0x01 0x4D 0x01 0x58 0x01
0x62 0x01 0x6C 0x01 0x74 0x01 0x7B 0x01 0x81 0x01 0x85 0x01 0x89 0x01 0x8B 0x01
0x8C 0x01 0x8B 0x01 0x89 0x01 0x85 0x01 0x81 0x01 0x7B 0x01 0x74 0x01 0x6C 0x01
0x62 0x01 0x58 0x01 0x4D 0x01 0x41 0x01 0x35 0x01 0x28 0x01 0x1B 0x01 0x0D 0x01
0x00 0x01 0x0D 0x00 0x1B 0x00 0x28 0x00 0x35 0x00 0x41 0x00 0x4D 0x00 0x58 0x00
0x62 0x00 0x6C 0x00 0x74 0x00 0x7B 0x00 0x81 0x00 0x85 0x00 0x89 0x00 0x8B 0x00
: get-cosine
# takes angle in v0,
# returns delta, magnitude in v0, v1
vf := 0b111111
v0 &= vf # mod 64
v0 <<= v0
i := cosine-table
i += v0
load v1
;
: get-angles
# takes angle in v3,
# unpacks x/y delta/mag into v4-v7
# cos(a) = cosine-table[(a % 64) << 1]
v0 := v3
get-cosine
v4 := v0 # x delta
v5 := v1 # x magnitude
# sin(a) = cosine-table[(a+16 % 64) << 1]
v0 := v3
v0 += 16
get-cosine
v6 := v0 # y delta
v7 := v1 # y magnitude
;
: delta-step
vf := 0
if v5 == 0 then va += v4 # positive x delta
if vf == 1 then vc += 1 # carry in
vf := 0
if v5 == 1 then va -= v4 # negative x delta
if vf == 0 then vc += -1 # borrow out
vf := 0
if v7 == 0 then vb += v6 # positive y delta
if vf == 1 then vd += 1 # carry in
vf := 0
if v7 == 1 then vb -= v6 # negative y delta
if vf == 0 then vd += -1 # borrow out
;
: heights
# {height, color}
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
: raycast
save-position
#v0-v1 are available as scratch.
v8 := 0 # loop index * 2
v3 := v9 # scan angle
v3 += -8
loop
get-angles
v2 := 16 # height+1
loop
delta-step
v2 += -1 # count down height
collision-test # returns result in v0
while v2 != 0
if v0 == 0 then
again
# save height and color in heights table:
i := heights
i += v8
v1 := v0
v0 := v2
save v1
vf := v3
restore-position
v3 := vf
v8 += 2
v3 += 1 # 16 slices * 5.625 = 90 degree FoV
if v8 != 32 then
again
;
###########################################
#
# Rendering
#
###########################################
# this 45-byte table allows me to construct all the necessary vertical
# strips using only immediate i and a height offset:
: top 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
: btm 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
: sync
# take advantage of the fact that vf
# is always a free register if we aren't
# doing any operations that can carry:
loop
vf := delay
if vf != 0 then
again
vf := 1
delay := vf
;
: draw-heights
# registers for draw loop:
# v0 is used to store the current height
# v1 stores the 'color' bitmask
v2 := 0 # heightmap index
v3 := 1 # upward strip Y
v4 := 16 # down strip Y
v5 := 0 # strip X (avoid shifting v1 in loop)
v6 := 15 # constant
sync clear
loop
# fetch height of column
i := heights
i += v2
load v1
# apply PWM duty cycle for 'color'
v1 &= ve
if v1 == 0 then v0 := 0
# draw upward strip
i := top
i += v0
v0 =- v6
sprite v5 v3 15
# draw downward strip
i := btm
i += v0
sprite v5 v4 15
# draw 16 columns
v2 += 2
v5 += 4
if v2 != 32 then
again
;
###########################################
#
# Main Loop
#
###########################################
: gun
0x10 0x18 0x24 0x24 0x24 0x24 0x5A 0xC2 0xE7 0x7F 0x3E 0x21 0x41 0x41
: spin-left
v9 += -1
raycast
;
: spin-right
v9 += 1
raycast
;
: walk-forward
v3 := v9
get-angles
delta-step
raycast
;
: walk-backward
v3 := v9
get-angles
vf := 1
v5 ^= vf
v7 ^= vf
delta-step
raycast
;
: main
# global state:
v9 := 30 # player angle
va := 128 # x position (fractional)
vb := 128 # y position (fractional)
vc := 5 # x position (whole)
vd := 5 # y position (whole)
ve := 0 # rolling frame counter
raycast
loop
draw-heights
i := gun
v0 := 38
v1 := 18
sprite v0 v1 14
ve += 1
v0 := 7
if v0 key then spin-left
v0 := 9
if v0 key then spin-right
v0 := 5
if v0 key then walk-forward
v0 := 8
if v0 key then walk-backward
again