Skip to content

Instantly share code, notes, and snippets.

@samneggs
Created February 13, 2022 06:33
Show Gist options
  • Save samneggs/9500c74e49d42e99e79125a9b1dea711 to your computer and use it in GitHub Desktop.
Save samneggs/9500c74e49d42e99e79125a9b1dea711 to your computer and use it in GitHub Desktop.
#----------------Based on YouTube-3DSage----------------------------------------
#Full video: https://youtu.be/PC1RaETIx3Y
import gc9a01
from machine import Pin, SPI, PWM, WDT
import framebuf
from time import sleep_ms, sleep_us, ticks_diff, ticks_us, sleep
from micropython import const
import array
from usys import exit
import gc
from math import sin,cos,pi,radians,tan
from random import randint
from uctypes import addressof
#-----------------------------MAP----------------------------------------------
MAXSCREEN_X = const(240)
MAXSCREEN_Y = const(200)
MAXSCREEN = const(MAXSCREEN_X*MAXSCREEN_Y*2)
YMAX= const(400) #400 # 320
mapX = const(8) #map width
mapY = const(8) #map height
mapS = const(64) #map cube size
SCALE = const(3)
UPDATE_SPEED = const(120)#20
TEXTURES = const(1)
BLUE = const(0x1f00)
BLACK = const(0)
WHITE = const(0xffff)
GREEN = const(0xe00A)
BROWN = const(0xe091)
RED = const(0x07e0)
YELLOW=const(0x00fe)
TEXTURE_HEIGHT = const(32*8) #47
TEXTURE_WIDTH = const(32) #90
#------joystck pin declaration-----
joyRight = Pin(17,Pin.IN)
joyDown = Pin(18,Pin.IN)
joySel = Pin(19,Pin.IN)
joyLeft = Pin(20,Pin.IN)
joyUp = Pin(21,Pin.IN)
display_buffer=bytearray(MAXSCREEN_X * MAXSCREEN_Y * 2)
tex_buff=bytearray(TEXTURE_WIDTH*TEXTURE_HEIGHT*2)
from raycast_maps2 import mapW_array,mapF_array,mapC_array
char_map=array.array('b',(
0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00, # U+0030 (0)
0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00, # U+0031 (1)
0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00, # U+0032 (2)
0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00, # U+0033 (3)
0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00, # U+0034 (4)
0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00, # U+0035 (5)
0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00, # U+0036 (6)
0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00, # U+0037 (7)
0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00, # U+0038 (8)
0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00)) # U+0039 (9)
isin=array.array('i',range(0,361))
icos=array.array('i',range(0,361))
itan=array.array('i',range(0,361))
# partx=array.array('i',range(0,100))
# party=array.array('i',range(0,100))
# partdx=array.array('i',range(0,100))
# partdy=array.array('i',range(0,100))
class Player():
def __init__(self):
self.px = 350
self.py = 250
self.pdx = 0
self.pdy = 0
self.pa = 70
self.floor = 0
player=Player()
# http://www.penguintutor.com/programming/picodisplayanimations
def blit_image_file(filename,width,height,cw,ch): # file width, file height, char width, char height
print(filename,gc.mem_free())
with open (filename, "rb") as file:
file_position = 0
char_position = 0
ecount = 0
current_byte = file.read(4) # header
while file_position < (width * height * 2):
current_byte = file.read(1)
# if eof
if len(current_byte) == 0:
break
# copy to buffer
tex_buff[char_position] = ord(current_byte) #and LCD.red
char_position += 1
file_position += 1
#if char_position == (cw * ch* 2):
# char_position = 0
file.close()
#screen.blit(texture,50,50)
#tft.blit_buffer(screen, 20, 0, MAXSCREEN_X, MAXSCREEN_Y)
#exit()
def init_isin(): # integer sin lookup table
for i in range(0,361):
isin[i]=int(sin(radians(i))*(1<<14))
def init_icos(): # integer cos lookup table
for i in range(0,361):
icos[i]=int(cos(radians(i))*(1<<14))
def init_itan(): # integer cos lookup table
for i in range(0,361):
itan[i]=int(tan(radians(i))*(1<<14))
def bl_ctrl(duty):
pwm = PWM(Pin(13))
pwm.freq(1000)
if(duty>=100):
pwm.duty_u16(65535)
else:
pwm.duty_u16(655*duty)
@micropython.viper
def screen_fps(n:int,p:int):
dest=ptr16(screen)#screen
c_map=ptr8(char_map)
huns = n//100
tens = int((0xcc_cccd*n)>>27) # n//10
ones = n-(tens*10) # n%10
row = 8
offset=p*8+50
while(row):
row-=1
col=8
while(col):
col-=1
r=(row*MAXSCREEN_X+col)+offset
#if c_map[(huns<<3)+row] & 1<<col:
# dest[r] = 0# 0xffff
if c_map[(tens<<3)+row] & 1<<col:
dest[r+8] = 0xffff
if c_map[(ones<<3)+row] & 1<<col:
dest[r+16] = 0xffff
def fade(input_color1, input_color2):
color1=input_color1<<8 | input_color1>>8 # byte swap to normal RBG565
red1 =color1>>11& 0b11111 # extract red #13
green1=color1>>6 & 0b11111 # extract green
blue1 =color1 & 0b11111 # extract blue
color2=input_color2<<8 | input_color2>>8 # byte swap
red2 =color2>>11& 0b11111 # extract red
green2=color2>>6 & 0b11111 # extract green
blue2 =color2 & 0b11111 # extract blue
inc_red =(red2- red1)/31 # find increment step
inc_green=(green2-green1)/31
inc_blue =(blue2- blue1)/31
for i in range(0,32):
red3 =red1 +int(i*inc_red) # build colors by steps
green3=green1+int(i*inc_green)
blue3 =blue1 +int(i*inc_blue)
color3=red3<<11 | green3<<6 | blue3 # combine RGB
color_l2.append((color3 & 0x00FF)<<8 | (color3>>8)) # byte swap to LCD RGB565
def Buttons(fps):
pushed=0
if(joyLeft.value() == 0): #(key=='a'):
player.pa=limit_deg(player.pa+UPDATE_SPEED//fps)
player.pdx=cos(radians(player.pa))
player.pdy=-sin(radians(player.pa))
#sprite.dx=int(player.pdx*(1<<14))
#sprite.dy=int(player.pdy*(1<<14))
if(joyRight.value() == 0): #(key=='d')
player.pa=limit_deg(player.pa-UPDATE_SPEED//fps)
player.pdx=cos(radians(player.pa))
player.pdy=-sin(radians(player.pa))
#sprite.dx=int(player.pdx*(1<<14))
#sprite.dy=int(player.pdy*(1<<14))
xo=0
if(player.pdx<0):
xo=-20
else:
xo=20 #x offset to check map
yo=0
if(player.pdy<0):
yo=-20
else:
yo=20 #y offset to check map
ipx=int(player.px>>6)
ipx_add_xo=int((player.px+xo)>>6)
ipx_sub_xo=int((player.px-xo)>>6) #x position and offset
ipy=int(player.py>>6)
ipy_add_yo=int((player.py+yo)>>6)
ipy_sub_yo=int((player.py-yo)>>6) #y position and offset
if(joyUp.value() == 0): #(key=='w'):
if(mapW_array[player.floor+ipy*mapX + ipx_add_xo]==0):
player.px+=int(player.pdx*UPDATE_SPEED//fps) #TURN_SPEED
if(mapW_array[player.floor+ipy_add_yo*mapX + ipx ]==0):
player.py+=int(player.pdy*UPDATE_SPEED//fps)
if(joyDown.value() == 0):#(key=='s'):
if(mapW_array[player.floor+ipy*mapX + ipx_sub_xo]==0):
player.px-=int(player.pdx*UPDATE_SPEED//fps)
if(mapW_array[player.floor+ipy_sub_yo*mapX + ipx ]==0):
player.py-=int(player.pdy*UPDATE_SPEED//fps)
if(joySel.value() == 0):
#screen.blit(texture,50,00)
if player.pdx<0:
xo=-25
else:
xo=25
if player.pdy<0:
yo=-25
else:
yo=25
ipx=player.px>>6
ipx_add_xo=int((player.px+xo)>>6)
ipy=player.py>>6
ipy_add_yo=int((player.py+yo)>>6)
#sprite.x=player.px<<14
#sprite.y=player.py<<14
# for i in range(100):
# partx[i]=player.px<<14
# party[i]=player.py<<14
# partdx[i]=int(player.pdx*(1<<14))+randint(-5000,5000)
# partdy[i]=int(player.pdy*(1<<14))+randint(-5000,5000)
#
if(mapW_array[player.floor+ipy_add_yo*mapX+ipx_add_xo]==4):
mapW_array[player.floor+ipy_add_yo*mapX+ipx_add_xo]=0
if(mapW_array[player.floor+ipy_add_yo*mapX+ipx_add_xo]==5):
player.floor+=64
gc.collect()
blit_image_file('floor'+str(player.floor>>6)+'.bin',32,32*8,32,32)
player.pa=limit_deg(player.pa+180)
return
if(mapW_array[player.floor+ipy_add_yo*mapX+ipx_add_xo]==6):
player.floor-=64
gc.collect()
blit_image_file('floor'+str(player.floor>>6)+'.bin',32,32*8,32,32)
player.pa=limit_deg(player.pa+180)
return
@micropython.viper
def draw_walls(lineH:int,tx:int,ty:int,shade:int,hmt:int,r:int,lineOff:int,ty_step:int,disH:int):
dest=ptr16(screen)
color_addr=ptr16(color_l2)
#all_addr=ptr8(All_Textures_array)
texture_addr=ptr16(tex_buff)
walls_ctl_addr=ptr32(walls_ctl)
y=0
r2=r<<2
tx2=tx%(31)
shade2=30-(disH>>4)
walls_ctl_addr[0] = lineH
walls_ctl_addr[1] = tx2
walls_ctl_addr[2] = ty
walls_ctl_addr[3] = shade2
walls_ctl_addr[4] = hmt
walls_ctl_addr[5] = r2
walls_ctl_addr[6] = lineOff
walls_ctl_addr[7] = ty_step
walls_ctl_addr[8] = disH
#walls_ctl_addr[9] = color
#walls_ctl_addr[10] = int(player.floor)
walls_ctl_addr[11] = 0x07e0f81f
walls_ctl_addr[12] = 0 #forground
walls_asm(dest,walls_ctl_addr,texture_addr)
return
LINEH_CTL = const(0) # lineH
TX2_CTL = const(4) # tx2
TY_CTL = const(8) # ty
SHADE_CTL = const(12) # shade
HMT_CTL = const(16) # hmt
R2_CTL = const(20) # r2
LINEOFF_CTL = const(24) # lineOff
TY_STEP_CTL = const(28) # ty_step
DISH_CTL = const(32) # disH
COLOR_CTL = const(36) # color2
FLOOR_CTLx = const(40) # player.floor
MAGIC2_CTL = const(44) # 0x07e0f81f
FG2_CTL = const(48) # forground color
walls_ctl=array.array('i',(0,4,8,12,16,20,24,28,32,36,40,0x07e0f81f,48,0,0))
@micropython.asm_thumb
def walls_asm(r0,r1,r2): # r0=screen, r1=CTL array, r2=texture_addr
ldr(r3,[r1,HMT_CTL]) # r4=hmt
cmp(r3,0)
beq(EXIT)
mov(r4,1)
lsl(r4,r4,11) # r4= 1<<11 = 2048 = 32*32*2
mul(r4,r3) # r4= hmt * 2048
add(r5,r2,r4) # r5= texture_addr += 32*32*2
mov(r2,0) # r2=y
label(LOOP)
# pos=((y+lineOff)>>1)*MAXSCREEN_X+r2
ldr(r3,[r1,LINEOFF_CTL]) # r3=lineOff
add(r3,r2,r3) # r3=y+lineOff
asr(r3,r3,1) # r3=(y+lineOff)>>1
mov(r4,MAXSCREEN_X)
mul(r3,r4) # r3=(y+lineOff)>>1*MAXSCREEN_X
ldr(r4,[r1,R2_CTL])
add(r3,r3,r4) # r4=(y+lineOff)>>1*MAXSCREEN_X+r2
add(r3,r3,r3) # double for 2 bytes per pixel
add(r7,r3,r0) # dest[...]
# color2=texture_addr[(((ty>>14)-(((ty>>14)>>5)<<5))<<5) + tx2 ]
label(TEXTURE)
ldr(r3,[r1,TY_CTL]) # r3=ty
ldr(r4,[r1,TY_STEP_CTL]) # r4=ty_step
add(r4,r4,r3) # ty+=ty_step
str(r4,[r1,TY_CTL]) #
asr(r3,r3,14) # r3= ty>>14
mov(r6,r3) # r6= ty>>14
asr(r6,r6,5) # r6= (ty>>14)>>5
lsl(r6,r6,5) # r6= ((ty>>14)>>5)<<5
sub(r6,r3,r6) # r6= (ty>>14)-(((ty>>14)>>5)<<5)
lsl(r6,r6,5) # r6= (ty>>14)-(((ty>>14)>>5)<<5)<<5
ldr(r3,[r1,TX2_CTL]) # r3=tx2
add(r6,r3,r6) # r6= (ty>>14)-(((ty>>14)>>5)<<5) + tx2
add(r6,r6,r6) # double for ldrh
add(r6,r5,r6) # r6= texture_addr[...]
ldrh(r6,[r6,0]) # r6= color
ldr(r3,[r1,HMT_CTL]) # r3=hmt
cmp(r3,6)
beq(DRAW_WALLS) # fire? skip shade
data(2,0b1011_1010_01_110_110) # r6=swap color bytes
mov(r3,r6) # r3,r6= fg
lsl(r6,r6,16) # fg << 16
orr(r6,r3) # fg | (fg << 16)
ldr(r3,[r1,MAGIC2_CTL]) # 0x07e0f81f
and_(r3,r6) # r3=(fg | (fg << 16)) & 0x07e0f81f
ldr(r4,[r1,FG2_CTL]) # bg
lsl(r6,r4,16) # bg << 16
orr(r6,r4) # bg | (bg << 16)
ldr(r4,[r1,MAGIC2_CTL]) # 0x07e0f81f
and_(r4,r6) # r4=(bg | (bg << 16)) & 0x07e0f81f
# bg = bg + (((fg-bg)*alpha)>> 5)
sub(r6,r3,r4) # (fg-bg)
ldr(r3,[r1,SHADE_CTL]) # alpha
mul(r6,r3) # ((fg-bg)*alpha)
asr(r6,r6,5) # (((fg-bg)*alpha)>> 5)
add(r4,r4,r6) # r4 = bg + (((fg-bg)*alpha)>> 5)
ldr(r3,[r1,MAGIC2_CTL])
and_(r4,r3) # bg = bg & 0x07e0f81f
mov(r3,r4) # r3 = bg
asr(r4,r4,16) # (bg >> 16)
orr(r4,r3) # bg | (bg >> 16)
mov(r6,1)
lsl(r6,r6,16) # 1<<16 = 0x10000
sub(r6,r6,1) # 0x10000-1 = 0xffff
and_(r4,r6) # r4 & 0xffff
mov(r6,r4)
label(DONE_SHADE)
data(2,0b1011_1010_01_110_110) # r6=swap color bytes
label(DRAW_WALLS)
strh(r6, [r7, 0]) # r7=screen
strh(r6, [r7, 2])
strh(r6, [r7, 4])
strh(r6, [r7, 6])
add(r2,r2,1) # y+=1
ldr(r3,[r1,LINEH_CTL])
cmp(r2,r3) # while y<lineH:
blt(LOOP)
label(EXIT)
@micropython.viper
def draw_floor(y:int,px:int,py:int,fixang:int,deg:int,r:int,shade:int):
dest=ptr16(screen)
cos_addr=ptr32(icos)
sin_addr=ptr32(isin)
mapf_addr=ptr8(mapF_array)
mapc_addr=ptr8(mapC_array)
color_addr=ptr16(color_l2)
texture_addr=ptr16(tex_buff)
floor_ctl_addr=ptr32(floor_ctl)
px2=px>>1
py2=py>>1
cos_deg=(cos_addr[deg]*200)*32 #158*32
sin_deg=(sin_addr[deg]*200)*32
cos_fixang=cos_addr[fixang]
r4=r<<2
floor_ctl_addr[0] = y
floor_ctl_addr[1] = px2
floor_ctl_addr[2] = py2
floor_ctl_addr[3] = cos_deg
floor_ctl_addr[4] = sin_deg
floor_ctl_addr[5] = cos_fixang
floor_ctl_addr[6] = r4
#floor_ctl_addr[7] = tx
#floor_ctl_addr[8] = ty
floor_ctl_addr[9] = 0 #denominator
floor_ctl_addr[10] = 0 # forground
floor_ctl_addr[11] = 0x07e0f81f
floor_ctl_addr[12] = shade # not used
floor_asm(dest,texture_addr,floor_ctl_addr)
return
while(y<400):
dy=y-200
tx=px2 + (cos_deg//(dy*cos_fixang))
ty=py2 - (sin_deg//(dy*cos_fixang))
#c=texture_addr[((ty%(32))*32) + (tx%(32))]
c=texture_addr[((ty-((ty>>5)<<5))<<5) + tx-((tx>>5)<<5) ]
pos=(y>>1)*MAXSCREEN_X+r4
if pos<MAXSCREEN:
dest[pos]=c
dest[pos+1]=c
dest[pos+2]=c
dest[pos+3]=c
y+=2
Y_CTL = const(0) # y
PX2_CTL = const(4) # px2
PY2_CTL = const(8) # py2
COS_DEG_CTL = const(12) # cos_deg
SIN_DEG_CTL = const(16) # sin_deg
COS_FIXANG_CTL = const(20) # cos_fixang
R4_CTL = const(24) # r4
TX_CTL = const(28) # tx
TY_CTL2 = const(32) # ty
DENOM_CTL = const(36) # dy*cos_fixang
FG_CTL = const(40) # forground color
MAGIC_NUM_CTL = const(44) # 0x07e0f81f
ALPHA_CTL = const(48) # alpha
floor_ctl=array.array('i',(0,4,8,12,16,20,24,28,32,36,40,44,48,0,0))
# y,px2,py2,cos_deg,sin_deg,cos_fixang,r4,tx,ty
@micropython.asm_thumb
def floor_asm(r0,r1,r2): # r0=screen, r1=texture_addr , r2=CTL array
align(2)
ldr(r6,[r2,Y_CTL]) # r6=y
# dy=y-200
# tx=px2 + (cos_deg//(dy*cos_fixang))
# ty=py2 - (sin_deg//(dy*cos_fixang))
label(MAINLOOP)
push({r0,r1}) # save r0,r1 for divide
mov(r3,r6)
sub(r3,200) # r3 dy=y-200
ldr(r4,[r2,COS_FIXANG_CTL]) #
mul(r4,r3) # r4=dy*cos_fixang
mov(r1,r4) # r1=dy*cos_fixang
str(r1,[r2, DENOM_CTL])
ldr(r0,[r2,COS_DEG_CTL]) # r0=cos_deg
bl(DIVIDE) # cos_deg//(dy*cos_fixang)
ldr(r1,[r2,PX2_CTL]) # px2
add(r0,r1,r0) # px2 + (cos_deg//(dy*cos_fixang))
str(r0,[r2, TX_CTL]) # tx=px2 + (cos_deg//(dy*cos_fixang))
ldr(r0,[r2,SIN_DEG_CTL]) # r0=sin_deg
ldr(r1,[r2,DENOM_CTL]) # r1=dy*cos_fixang
bl(DIVIDE)
ldr(r1,[r2,PY2_CTL]) # py2
sub(r0,r1,r0) # py2 - (sin_deg//(dy*cos_fixang))
str(r0,[r2,TY_CTL2]) # ty=py2 - (sin_deg//(dy*cos_fixang))
# c=texture_addr[((ty-((ty>>5)<<5))<<5) + tx-((tx>>5)<<5) ]
mov(r1,r0) # r1=ty
asr(r0,r0,5) # r0= ty>>5
lsl(r0,r0,5) # r0= (ty>>5)<<5
sub(r0,r1,r0) # r0= (ty)- ((ty>>5)<<5)
lsl(r0,r0,5) # r0= (ty)-(((ty>>5)<<5)<<5
ldr(r1,[r2,TX_CTL]) # r1=tx
mov(r3,r1) # r3=tx
asr(r1,r1,5) # tx>>5
lsl(r1,r1,5) # (tx>>5)<<5
sub(r1,r3,r1) # r1= (tx)-((tx>>5)<<5)
add(r4,r0,r1) # r4= (((ty)-(((ty>>5)<<5))<<5) + tx-((tx>>5)<<5)
pop({r0,r1}) # get r0,r1 back
add(r4,r4,r4) # double for color
add(r4,r4,r1) # add to texture base address
ldrh(r3,[r4,0]) # r3=color
data(2,0b1011_1010_01_011_011) # r3=swap color bytes
# fg = (fg | (fg << 16)) & 0b00000111111000001111100000011111 # 0x07e0f81f
# bg = (bg | (bg << 16)) & 0b00000111111000001111100000011111 # 0x07e0f81f
# bg = bg + (((fg-bg)*alpha)>> 5)
# bg = bg & 0x07e0f81f
# bg = bg | (bg >> 16) # gggbbbbb_rrrrrggg
# bg = (bg>>8) | ((bg<<8) & 0xffff)
mov(r5,r3)
lsl(r4,r5,16) # fg << 16
orr(r4,r5) # fg | (fg << 16)
ldr(r5,[r2,MAGIC_NUM_CTL]) # 0x07e0f81f
and_(r5,r4) # r5=(fg | (fg << 16)) & 0x07e0f81f
ldr(r4,[r2,FG_CTL])#### #
# bg
lsl(r7,r4,16) # bg << 16
orr(r7,r4) # bg | (bg << 16)
ldr(r4,[r2,MAGIC_NUM_CTL]) # 0x07e0f81f
and_(r4,r7) # r4=(bg | (bg << 16)) & 0x07e0f81f
# bg = bg + (((fg-bg)*alpha)>> 5)
sub(r5,r5,r4) # (fg-bg)
#ldr(r3,[r2,ALPHA_CTL]) # alpha
mov(r7,r6)######
asr(r7,r7,3)####
sub(r7,25)
mul(r5,r7) # ((fg-bg)*alpha)>> 5
asr(r5,r5,5) # (((fg-bg)*alpha)>> 5)
add(r4,r4,r5) # r4 = bg + (((fg-bg)*alpha)>> 5)
ldr(r7,[r2,MAGIC_NUM_CTL])
and_(r4,r7) # bg = bg & 0x07e0f81f
mov(r7,r4) # r7 = bg
asr(r4,r4,16) # (bg >> 16)
orr(r4,r7) # bg | (bg >> 16)
mov(r5,1)
lsl(r5,r5,16) # 1<<16 = 0x10000
sub(r5,r5,1) # 0x10000-1 = 0xffff
and_(r4,r5) # r4 & 0xffff
mov(r3,r4)
label(DONE_SHADE)
data(2,0b1011_1010_01_011_011) # r4=swap color bytes
# pos=(y>>1)*MAXSCREEN_X+r4
asr(r4,r6,1) # y>>1
mov(r5,MAXSCREEN_X) # MAXSCREEN_X
mul(r4,r5) # (y>>1)*MAXSCREEN_X
ldrh(r5,[r2,R4_CTL])
add(r4,r4,r5) # (y>>1)*MAXSCREEN_X+r4
add(r4,r4,r4) # double
add(r4,r0,r4) # add to base address of screen
strh(r3,[r4,0])
strh(r3,[r4,2])
strh(r3,[r4,4])
strh(r3,[r4,6])
b(SKIP) # ceiling ------------------------
mov(r7,200) # r7=200
lsl(r7,r7,1) # r7=400
sub(r7,r7,r6) # 400-y
asr(r4,r7,1) # y>>1
mov(r5,MAXSCREEN_X) # MAXSCREEN_X
mul(r4,r5) # (y>>1)*MAXSCREEN_X
ldrh(r5,[r2,R4_CTL])
add(r4,r4,r5) # (y>>1)*MAXSCREEN_X+r4
add(r4,r4,r4) # double
add(r4,r0,r4) # add to base address of screen
strh(r3,[r4,0])
strh(r3,[r4,2])
strh(r3,[r4,4])
strh(r3,[r4,6])
label(SKIP) #------------end ceiling----------
add(r6,r6,2) # y+=2
mov(r7,200) # (y<400):
lsl(r7,r7,1)
cmp(r6,r7)
blt(MAINLOOP)
b(EXIT)
# -------------------divide routine----------r0=r0//r1-------------
label(DIVIDE)
mov(r3,0xd0)
lsl(r3,r3,24) # 0d0000000
add(r3,0x60) # offset so strh will work
str(r0, [r3, 8]) # SIO_DIV_SDIVIDEND_OFFSET _u(0x00000068)8 / 60 unsigned
str(r1, [r3, 12]) # SIO_DIV_SDIVISOR_OFFSET _u(0x0000006c)12 / 64
b(DELAY1)
label(DELAY1)
b(DELAY2)
label(DELAY2)
b(DELAY3)
label(DELAY3)
b(DELAY4)
label(DELAY4)
ldr(r1, [r3, 20]) #SIO_DIV_REMAINDER_OFFSET _u(0x00000074)20
ldr(r0, [r3, 16]) #SIO_DIV_QUOTIENT_OFFSET _u(0x00000070)16
bx(lr)
#----------------end divide-------------------------------------
label(EXIT)
@micropython.viper
def limit_deg(deg:int)->int:
if(deg>359):
deg-=360
if(deg<0):
deg+=360
return deg
#rx,ry,disV,vmt
RX_IND = const(0)
RY_IND = const(1)
DISV_IND = const(2)
VMT_IND = const(3)
output_array=array.array('i',(0,0,0,0))
@micropython.viper
def test_ray1(ra:int):
cos_addr=ptr32(icos)
sin_addr=ptr32(isin)
tan_addr=ptr32(itan)
color_addr=ptr16(color_l2)
mapW_addr=ptr8(mapW_array)
outputs_addr=ptr32(output_array)
pa=int(player.pa)
px=int(player.px)
py=int(player.py)
vmt=0
hmt=0 #vertical and horizontal map texture number
dof=0
side=0
disV=100000
cos_ra=cos_addr[ra]
sin_ra=sin_addr[ra]
Tan=tan_addr[ra]
if cos_ra > 16: # 0.001:
rx=((px>>6)<<6)+64
ry=(((px-rx)*Tan)>>14)+py
xo= 64
yo=-1*((xo*Tan)>>14) #looking left
elif cos_ra< -16: #-0.001:
rx=((px>>6)<<6)-1 #-0.0001 <--!!!!
ry=(((px-rx)*Tan)>>14)+py
xo=-64
yo=-1*((xo*Tan)>>14) #looking right
else:
rx=px
ry=py
dof=8 #looking up or down. no hit
while(dof<8):
mx=int(rx)>>6
my=int(ry)>>6
mp=my*mapX+mx
if(mp>0 and mp<mapX*mapY and mapW_addr[int(player.floor)+mp]>0):
vmt=mapW_addr[int(player.floor)+mp]-1
dof=8
disV=((cos_ra*(rx-px))>>14)-((sin_ra*(ry-py))>>14) #hit
else:
rx+=xo
ry+=yo
dof+=1 #check next horizontal
outputs_addr[RX_IND]=rx
outputs_addr[RY_IND]=ry
outputs_addr[DISV_IND]=disV
outputs_addr[VMT_IND]=vmt
# rx,ry,disV,vmt
@micropython.viper
def draw_rays():
#int r,mx,my,mp,dof,side; float vx,vy,rx,ry,ra,xo,yo,disV,disH;
cos_addr=ptr32(icos)
sin_addr=ptr32(isin)
tan_addr=ptr32(itan)
color_addr=ptr16(color_l2)
mapW_addr=ptr8(mapW_array)
inputs_addr=ptr32(output_array)
pa=int(player.pa)
px=int(player.px)
py=int(player.py)
ra=int(limit_deg(pa+30)) #ray set back 30 degrees
for r in range(60):
#---Vertical---
vmt=0
hmt=0 #vertical and horizontal map texture number
dof=0
disV=100000
cos_ra=cos_addr[ra]
sin_ra=sin_addr[ra]
Tan=tan_addr[ra]
test_ray1(ra)
rx=int(inputs_addr[RX_IND])
ry=int(inputs_addr[RY_IND])
disV=int(inputs_addr[DISV_IND])
vmt=int(inputs_addr[VMT_IND])
vx=rx
vy=ry
#---Horizontal---
dof=0
disH=100000
if Tan!=0:
Tan=((1<<28)//Tan)
if sin_ra> 16: #0.001:
ry=((py>>6)<<6) -1 #-0.0001 <--!!!
rx=(((py-ry)*Tan)>>14)+px
yo= -64
xo=-1*((yo*Tan)>>14) #looking up
elif sin_ra < -16: #-0.001:
ry=((py>>6)<<6)+64
rx=(((py-ry)*Tan)>>14)+px
yo= 64
xo=-1*((yo*Tan)>>14) #looking down
else:
rx=px
ry=py
dof=8 #looking straight left or right
while(dof<8):
mx=rx>>6
my=ry>>6
mp=my*mapX+mx
if(mp>0 and mp<(mapX*mapY) and mapW_addr[int(player.floor)+mp]>0):
hmt=mapW_addr[int(player.floor)+mp]-1
dof=8
disH=((cos_ra*(rx-px))>>14)-((sin_ra*(ry-py))>>14)
else:
rx+=xo
ry+=yo
dof+=1 #check next horizontal
shade=1
color=RED
if(disV<disH):
hmt=vmt
shade=2 # 0.5
rx=vx
ry=vy
disH=disV
#screen.line(int(px//SCALE),int(py//SCALE),int(rx//SCALE),int(ry//SCALE),GREEN) #draw 2D ray
ca=int(limit_deg(pa-ra))
disH=(disH*cos_addr[ca])>>14 #fix fisheye
lineH = ((mapS*YMAX))//disH
if lineH!=0:
ty_step=(32<<14)//lineH
ty_off=0
if(lineH>YMAX):
ty_off=(lineH-YMAX)>>1
lineH=YMAX #Line height and limit
lineOff = int(200 - (lineH>>1)) #line offset (160)
#Draw Walls
tx=0
ty=(ty_off*ty_step)+((hmt*32)<<14)
if shade==1:
tx=int(rx>>1)%32
if ra>180:
tx=31-tx
else:
tx=int(ry>>1)%32
if ra>90 and ra<270:
tx=31-tx
draw_walls(lineH,tx,ty,shade,hmt,r,lineOff,ty_step,disH) # 800uS
#---draw floors---
y=lineOff+lineH
fixang=int(limit_deg(pa-ra))
draw_floor(y,px,py,fixang,ra,r,disH>>4)
#screen.fill_rect((r*4),lineOff//SCALE,4,(lineH)>>1,color_addr[int(disH)>>4]) # fast shaded line walls KEEP
ra=int(limit_deg(ra-1)) #go to next ray
fire_rgb = array.array('H',(8192 ,24616 ,41040 ,57456 ,24729 ,8378 ,24794 ,
41178 ,57554 ,25035 ,57803 ,8900 ,41924 ,
58300 ,9405 ,26037 ,42677 ,62430 ,65535))
fire_buff=bytearray(32*32*2)
W_TEXTURE = const(4)
W_FIRE = const(8)
W_COLOR = const(12)
W_RANDINT = const(16)
@micropython.asm_thumb
def fire_asm(r0): # fire_ctl (tex_buff,fire_buff,color_l2)
mov(r1,31*2) #31 # r1=x
lsl(r4,r1,5) # 31*32
label(BASELINE)
ldr(r2,[r0,W_FIRE]) # r2= fire_buff[] address
mov(r3,15*2) # color index 15*2
add(r2,r2,r4)
add(r2,r2,r1) #
strh(r3,[r2,0]) # fire_buff[index]=15*2
sub(r1,r1,2) # index-=2
cmp(r1,0)
bge(BASELINE)
mov(r1,0) # r1=x
label(X_LOOP)
mov(r2,0) # r2=y
label(Y_LOOP)
lsl(r3,r2,5) # y*32
add(r3,r3,r1) # y*32+x
add(r3,r3,r3) # double for ldrh
ldr(r5,[r0,W_FIRE]) # fire_addr[]
cmp(r3,0)
ble(NO_64)
add(r3,r3,r5) # r3=fire_addr[f_from] address
mov(r5,64)
sub(r5,r3,r5)
b(NO_64_ELSE)
label(NO_64)
add(r3,r3,r5)
#sub(r5,r3,r5) # r5=fire_addr[f_from-32] address
label(NO_64_ELSE)
ldrh(r4,[r3,0]) # r4=fire_addr[f_from] data
cmp(r4,0)
bgt(NOTZERO)#bne
mov(r6,0)
strh(r6,[r5,0]) # r5=fire_addr[f_from-32]=0
b(DONE)
label(NOTZERO)
ldr(r6,[r0,W_RANDINT]) # randint(0,3))
ldr(r7,[r6,0]) # reads one random bit
lsl(r7,r7,1)
ldr(r6,[r6,0])
orr(r6,r7)
add(r6,r6,r6) # double
add(r5,r5,2)
sub(r5,r5,r6)
ldr(r6,[r0,W_RANDINT]) # randint(0,3)) & 1
ldr(r7,[r6,0]) # reads one random bit
lsl(r7,r7,1)
ldr(r6,[r6,0])
orr(r6,r7)
mov(r7,1)
and_(r6,r7) # randint(0,3)) & 1
add(r6,r6,r6) # double
sub(r4,r4,r6)
cmp(r4,0)#####
blt(DONE)#####
strh(r4,[r5,0]) # r5=fire_addr[f_from+32]=fire_addr[f_from]
ldr(r6,[r0,W_COLOR]) # rgb_addr[] address
add(r6,r6,r4) # rgb_addr[fire_addr[f_to]]
mov(r7,1)
bic(r6,r7)
ldrh(r7,[r6,0]) # r7=rgb_addr[fire_addr[f_to]]
ldr(r6,[r0,W_TEXTURE]) # texture_addr[] address
mov(r3,6) #
lsl(r3,r3,10) # 6<<10= 32*32*6
lsl(r5,r2,5) # r5= y*32
add(r5,r5,r1) # = y*32+x
add(r5,r5,r3) # = y*32+x+32*32*2*2
#sub(r5,32)
#add(r5,32)#####
add(r5,r5,r5) # double for strh
add(r5,r5,r6) # texture_addr[32*32*2+y*32+x]
strh(r7,[r5,0]) # texture_addr[-32+32*32*6+y*32+x] = rgb_addr[fire_addr[f_to]]
label(DONE)
add(r2,r2,1) #
cmp(r2,32) #31
blt(Y_LOOP) # next y
add(r1,r1,1)
cmp(r1,31) #32
blt(X_LOOP) # next x
label(EXIT)
water_buff=bytearray(32*32*2)
#W_TEXTURE = const(4)
W_WATER = const(8)
#W_COLOR = const(12)
#W_RANDINT = const(16)
@micropython.asm_thumb
def water_asm(r0): # water_ctl (tex_buff,water_buff,color_l2)
mov(r1,30*2) # r1=x
label(BASELINE)
ldr(r2,[r0,W_WATER]) # r2= water_buff[] address
mov(r3,15*2) # color index 15*2
add(r2,r2,r1) #
strh(r3,[r2,0]) # water_buff[index]=15*2
sub(r1,r1,2) # index-=2
cmp(r1,0)
bge(BASELINE)
mov(r1,31) # r1=x
label(X_LOOP)
mov(r2,31) # r2=y
label(Y_LOOP)
lsl(r3,r2,5) # y*32
add(r3,r3,r1) # y*32+x
add(r3,r3,r3) # double for ldrh
ldr(r5,[r0,W_WATER]) # water_addr[]
add(r3,r3,r5) # r3=water_addr[f_from] address
ldrh(r4,[r3,0]) # r4=water_addr[f_from] data
mov(r5,64)
add(r5,r5,r3) # r5=water_addr[f_from+32] address
cmp(r4,0)
bne(NOTZERO)
mov(r6,0)
strh(r6,[r5,0]) # r5=water_addr[f_from+32]=0
b(DONE)
label(NOTZERO)
ldr(r6,[r0,W_RANDINT]) # randint(0,3)) & 1
ldr(r7,[r6,0]) # reads one random bit
lsl(r7,r7,1)
ldr(r6,[r6,0])
orr(r6,r7)
mov(r7,1)
and_(r6,r7) # randint(0,3)) & 1
add(r6,r6,r6) # double
sub(r4,r4,r6)
strh(r4,[r5,0]) # r5=water_addr[f_from+32]=water_addr[f_from]
ldr(r6,[r0,W_COLOR]) # rgb_addr[] address
mov(r7,24) # 12*2
add(r6,r6,r7)
add(r6,r6,r4) # rgb_addr[water_addr[f_to]]
mov(r7,1)
bic(r6,r7)
ldrh(r7,[r6,0]) # r7=rgb_addr[water_addr[f_to]+12]
ldr(r6,[r0,W_TEXTURE]) # texture_addr[] address
mov(r3,1) #
lsl(r3,r3,11) # 1<<11=2048 32*32*2
lsl(r5,r2,5) # r5= y*32
add(r5,r5,r1) # = y*32+x
add(r5,r5,r3) # = y*32+x+32*32*2*2
add(r5,r5,r5) # double for strh
add(r5,r5,r6) # texture_addr[32*32*2+y*32+x]
strh(r7,[r5,0]) # texture_addr[32*32*2+y*32+x] = rgb_addr[water_addr[f_to]+12]
label(DONE)
sub(r2,r2,1) #
bpl(Y_LOOP) # next y
sub(r1,r1,1)
bpl(X_LOOP) # next x
label(EXIT)
if __name__=='__main__':
spi = SPI(1, baudrate=63_000_000, sck=Pin(10), mosi=Pin(11))
tft = gc9a01.GC9A01(
spi,
MAXSCREEN_X,
240,
reset=Pin(12, Pin.OUT),
cs=Pin(9, Pin.OUT),
dc=Pin(8, Pin.OUT),
backlight=Pin(13, Pin.OUT),
rotation=0)
tft.init()
tft.rotation(0)
tft.fill(gc9a01.BLACK)
bl_ctrl(50)
sleep(0.5)
screen=framebuf.FrameBuffer(display_buffer, MAXSCREEN_X , MAXSCREEN_Y, framebuf.RGB565)
texture=framebuf.FrameBuffer(tex_buff,TEXTURE_WIDTH,TEXTURE_HEIGHT,framebuf.RGB565)
blit_image_file('floor'+str(player.floor>>6)+'.bin',32,32*8,32,32)
fps=0
color_l2 = array.array('H', [])
fade(WHITE,BLUE) # 0
init_isin()
init_icos()
init_itan()
wdt = WDT(timeout=8300) # Watchdog timer reset
gticks=ticks_us()
water_ctl=array.array('I',(0,addressof(tex_buff),addressof(water_buff),addressof(color_l2),0x4006001c,0,0,0))
fire_ctl =array.array('I',(0,addressof(tex_buff),addressof( fire_buff),addressof(fire_rgb),0x4006001c,0,0,0))
while(1):
wdt.feed()
screen.fill_rect(0,0,MAXSCREEN_X-1,90,BLACK) #1480 uS sky
#screen.fill_rect(0,90,MAXSCREEN_X,MAXSCREEN_X-50,GREEN) #solid floor
draw_rays() # 50000 uS
Buttons(fps+1) # 800uS
screen_fps(fps,8) # 180uS
water_asm(water_ctl)
fire_asm(fire_ctl)
tft.blit_buffer(screen, 0, 20, MAXSCREEN_X, MAXSCREEN_Y) # 16600uS 240x200
fps=1_000_000//ticks_diff(ticks_us(), gticks)
gticks=ticks_us()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment