scroll left and right work in stdef and hidef adds octo test roms adds schip fonts to memory
311 lines
6.3 KiB
Plaintext
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
|