Skip to content

Instantly share code, notes, and snippets.

@samneggs
Created May 22, 2022 23:46
Show Gist options
  • Save samneggs/f8b353756bedde202b34b3396c676e61 to your computer and use it in GitHub Desktop.
Save samneggs/f8b353756bedde202b34b3396c676e61 to your computer and use it in GitHub Desktop.
Falling Sand and Water
import gc9a01
from gc9a01 import color565
from machine import Pin, SPI, PWM, WDT, freq
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 random import randint
from uctypes import addressof
import _thread
MAXSCREEN_X = const(240)
MAXSCREEN_Y = const(240)
display_buffer=bytearray(MAXSCREEN_X * MAXSCREEN_Y * 2)
text_buffer=bytearray(8*80*2)
DONE=False
RIGHT=False
def bl_ctrl(duty):
pwm = PWM(Pin(13))
pwm.freq(1000)
if(duty>=100):
pwm.duty_u16(65535)
else:
pwm.duty_u16(655*duty)
# http://www.penguintutor.com/programming/picodisplayanimations
def blit_image_file(filename,width,height): # file width, file height
#print(filename,gc.mem_free())
with open (filename, "rb") as file:
file_position = 0
char_position = 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)
char_position += 1
file_position += 1
file.close()
#screen.blit(texture,50,50)
#tft.blit_buffer(screen, 20, 0, MAXSCREEN_X, MAXSCREEN_Y)
#exit()
def blocks():
for i in range(10):
dx=20
min_y=120
screen.fill_rect(randint(0,220),randint(min_y,220),10,10,0xffff)
x=randint(50,220)
y=randint(min_y,220)
screen.line(x,y,x+dx,y+dx,0xffff)
screen.line(x,y+1,x+dx,y+dx+1,0xffff)
x=randint(50,220)
y=randint(min_y,220)
screen.line(x,y,x-dx,y+dx,0xffff)
screen.line(x,y+1,x-dx,y+dx+1,0xffff)
@micropython.viper
def sand2():
screen_addr=ptr16(display_buffer)
for y in range(220,0,-1):
for x in range(0,240):
source=y*MAXSCREEN_X+x-MAXSCREEN_X
sourcecolor=screen_addr[source]
if sourcecolor == 0xff00 or sourcecolor == 0:
continue
dest=y*MAXSCREEN_X+x
destcolor=screen_addr[dest]
if destcolor == 0:
screen_addr[source] = 0
screen_addr[dest] = sourcecolor
elif screen_addr[source+1+MAXSCREEN_X] == 0:
screen_addr[source] = 0
screen_addr[source+1+MAXSCREEN_X] = sourcecolor
elif screen_addr[source-1+MAXSCREEN_X] == 0:
screen_addr[source] = 0
screen_addr[source-1+MAXSCREEN_X] = sourcecolor
@micropython.asm_thumb
def water_lasm(r0):
mov(r1,239) # r1 = y
label(LOOP_Y)
mov(r7,255) # stack marker
push({r7})
mov(r7,1)
mov(r2,r1)
and_(r2,r7)
bne(LEFT2RIGHT)
mov(r2,120) # max x
b(LOOP_X)
label(LEFT2RIGHT)
mov(r2,0) # r2 = x
label(LOOP_X)
mov(r3,240) # 240
mul(r3,r1) # 240*y
add(r3,r3,r2) # 240*y+x
mov(r4,r3)
sub(r4,240) # -XMAX
add(r3,r3,r3) # double ldrh
add(r3,r3,r0) # r3 = dest addr
add(r4,r4,r4) # double ldrh
add(r4,r4,r0) # r4 = source addr
ldrh(r5,[r4,0]) # r5 = sourcecolor
cmp(r5,0)
beq(NEXT_X) # skip if source=0
mov(r7,0x1)
lsl(r7,r7,16)
sub(r7,1) # 0xffff
cmp(r5,r7)
beq(NEXT_X) # skip if source=0xffff
ldrh(r6,[r3,0]) # r6=destcolor
cmp(r6,0)
beq(MOVEDOWN) # move down if dest=0
mov(r7,255)
lsl(r7,r7,8) # 0xff00 water color
cmp(r7,r5)
beq(TRYPLUS1) # try move diag if source=water
cmp(r5,0xff) # 0x00ff=yellow
beq(YELLOW)
b(NEXT_X)
label(YELLOW)
cmp(r6,r7) # is dest water?
bne(TRYPLUS1)
strh(r7,[r4,0]) # source = 0
strh(r5,[r3,0]) # dest = sourcecolor
b(NEXT_X)
label(MOVEDOWN)
mov(r6,0)
strh(r6,[r4,0]) # source = 0
strh(r5,[r3,0]) # dest = sourcecolor
b(NEXT_X)
label(TRYPLUS1)
mov(r3,r4) # source
mov(r6,241) # 1 + MAX_X
add(r6,r6,r6) # double ldrh
add(r3,r3,r6) # source + 1 + MAX_X
ldrh(r6,[r3,0]) # r6=diag color
cmp(r6,0)
beq(DIAGRIGHT)
cmp(r6,0x0) # if empty move diag
beq(DIAGRIGHT)
cmp(r6,r7) # if water move diag
bne(TRYMINUS1)
cmp(r5,0xff) # if sand move diag
bne(TRYMINUS1)
label(DIAGRIGHT) # move diag to right
#mov(r6,0)
strh(r6,[r4,0]) # source = 0
strh(r5,[r3,0]) # source + 1 + MAX_X = sourcecolor
b(NEXT_X)
label(TRYMINUS1)
sub(r3,4) # source-1+MAXSCREEN_X
ldrh(r6,[r3,0])
cmp(r6,0) # is diag empty?
beq(DIAGLEFT)
cmp(r5,r7) # is source water
beq(SAVE_WATER)
cmp(r6,r7) # is dest water?
beq(DIAGLEFT)
b(SAVE_WATER)
label(DIAGLEFT)
strh(r6,[r4,0]) # source = 0
strh(r5,[r3,0]) # source - 2 + MAX_X = sourcecolor
b(NEXT_X)
label(SAVE_WATER)
cmp(r5,0xff) # is sand?
beq(NEXT_X)
mov(r7,r2)
push({r7})
label(NEXT_X)
mov(r7,1)
mov(r6,r1)
and_(r6,r7)
bne(LEFT2RIGHT1)
sub(r2,1)
bne(LOOP_X)
b(WATER)
label(LEFT2RIGHT1)
add(r2,1)
cmp(r2,120) # max x
bne(LOOP_X)
label(WATER) #------DO WATER LEFT/RIGHT----------
pop({r7})
cmp(r7,255)
beq(WATER_DONE)
add(r7,1)
mov(r4,r1)
sub(r4,1)
mov(r3,240) # 240
mul(r3,r4) # 240*y
add(r3,r3,r7) # 240*y+x
sub(r3,2) # 240*y+x-2
add(r3,r3,r3) # double ldrh
add(r3,r3,r0) # r3 = dest addr
ldrh(r5,[r3,2]) # r5 = source color
label(RANDOM)
align(4)
mov(r7,pc)
b(RANDBIT_ADDR)
data(2,0x001c,0x4006)
align(4)
label(RANDBIT_ADDR)
ldr(r7,[r7,0]) # get random addr
ldr(r7,[r7,0]) # get random bit
cmp(r7,1) # choose left/right first
beq(LEFT_FIRST)
b(TEST_RIGHT2)
label(LEFT_FIRST)
b(TEST_LEFT)
label(TEST_LEFT)
ldrh(r4,[r3,0]) # r4 = left dest color
cmp(r4,0)
bne(TEST_RIGHT)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,0]) # move color to left
b(WATER)
label(TEST_RIGHT)
ldrh(r4,[r3,4]) # r4 = right dest color
cmp(r4,0)
bne(WATER)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,4]) # move color to right
b(WATER)
label(TEST_RIGHT2)
ldrh(r4,[r3,4]) # r4 = right dest color
cmp(r4,0)
bne(TEST_LEFT2)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,4]) # move color to right
b(WATER)
label(TEST_LEFT2)
ldrh(r4,[r3,0]) # r4 = left dest color
cmp(r4,0)
bne(WATER)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,0]) # move color to left
b(WATER)
label(WATER_DONE)
sub(r1,1)
beq(EXIT)
b(LOOP_Y)
label(EXIT)
@micropython.asm_thumb
def water_rasm(r0):
mov(r1,239) # r1 = y
label(LOOP_Y)
mov(r7,255) # stack marker
push({r7})
mov(r7,1)
mov(r2,r1)
and_(r2,r7)
bne(LEFT2RIGHT)
mov(r2,240) # max x
b(LOOP_X)
label(LEFT2RIGHT)
mov(r2,120) # r2 = x
label(LOOP_X)
mov(r3,240) # 240
mul(r3,r1) # 240*y
add(r3,r3,r2) # 240*y+x
mov(r4,r3)
sub(r4,240) # -XMAX
add(r3,r3,r3) # double ldrh
add(r3,r3,r0) # r3 = dest addr
add(r4,r4,r4) # double ldrh
add(r4,r4,r0) # r4 = source addr
ldrh(r5,[r4,0]) # r5 = sourcecolor
cmp(r5,0)
beq(NEXT_X) # skip if source=0
mov(r7,0x1)
lsl(r7,r7,16)
sub(r7,1) # 0xffff
cmp(r5,r7)
beq(NEXT_X) # skip if source=0xffff
ldrh(r6,[r3,0]) # r6=destcolor
cmp(r6,0)
beq(MOVEDOWN) # move down if dest=0
mov(r7,255)
lsl(r7,r7,8) # 0xff00 water color
cmp(r7,r5)
beq(TRYPLUS1) # try move diag if source=water
cmp(r5,0xff) # 0x00ff=yellow
beq(YELLOW)
b(NEXT_X)
label(YELLOW)
cmp(r6,r7) # is dest water?
bne(TRYPLUS1)
strh(r7,[r4,0]) # source = 0
strh(r5,[r3,0]) # dest = sourcecolor
b(NEXT_X)
label(MOVEDOWN)
mov(r6,0)
strh(r6,[r4,0]) # source = 0
strh(r5,[r3,0]) # dest = sourcecolor
b(NEXT_X)
label(TRYPLUS1)
mov(r3,r4) # source
mov(r6,241) # 1 + MAX_X
add(r6,r6,r6) # double ldrh
add(r3,r3,r6) # source + 1 + MAX_X
ldrh(r6,[r3,0]) # r6=diag color
cmp(r6,0)
beq(DIAGRIGHT)
cmp(r6,0x0) # if empty move diag
beq(DIAGRIGHT)
cmp(r6,r7) # if water move diag
bne(TRYMINUS1)
cmp(r5,0xff) # if sand move diag
bne(TRYMINUS1)
label(DIAGRIGHT) # move diag to right
#mov(r6,0)
strh(r6,[r4,0]) # source = 0
strh(r5,[r3,0]) # source + 1 + MAX_X = sourcecolor
b(NEXT_X)
label(TRYMINUS1)
sub(r3,4) # source-1+MAXSCREEN_X
ldrh(r6,[r3,0])
cmp(r6,0) # is diag empty?
beq(DIAGLEFT)
cmp(r5,r7) # is source water
beq(SAVE_WATER)
cmp(r6,r7) # is dest water?
beq(DIAGLEFT)
b(SAVE_WATER)
label(DIAGLEFT) # move diag to left
strh(r6,[r4,0]) # source = 0
strh(r5,[r3,0]) # source - 2 + MAX_X = sourcecolor
b(NEXT_X)
label(SAVE_WATER)
cmp(r5,0xff) # is sand?
beq(NEXT_X)
mov(r7,r2)
push({r7})
label(NEXT_X)
mov(r7,1)
mov(r6,r1)
and_(r6,r7)
bne(LEFT2RIGHT1)
sub(r2,1)
cmp(r2,120)
bne(LOOP_X)
b(WATER)
label(LEFT2RIGHT1)
add(r2,1)
cmp(r2,240) # max x
bne(LOOP_X)
label(WATER) #------DO WATER LEFT/RIGHT----------
pop({r7})
cmp(r7,255)
beq(WATER_DONE)
add(r7,1)
mov(r4,r1)
sub(r4,1)
mov(r3,240) # 240
mul(r3,r4) # 240*y
add(r3,r3,r7) # 240*y+x
sub(r3,2) # 240*y+x-2
add(r3,r3,r3) # double ldrh
add(r3,r3,r0) # r3 = dest addr
ldrh(r5,[r3,2]) # r5 = source color
label(RANDOM)
align(4)
mov(r7,pc)
b(RANDBIT_ADDR)
data(2,0x001c,0x4006)
align(4)
label(RANDBIT_ADDR)
ldr(r7,[r7,0]) # get random addr
ldr(r7,[r7,0]) # get random bit
cmp(r7,1) # choose left/right first
beq(LEFT_FIRST)
b(TEST_RIGHT2)
label(LEFT_FIRST)
b(TEST_LEFT)
label(TEST_LEFT)
ldrh(r4,[r3,0]) # r4 = left dest color
cmp(r4,0)
bne(TEST_RIGHT)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,0]) # move color to left
b(WATER)
label(TEST_RIGHT)
ldrh(r4,[r3,4]) # r4 = right dest color
cmp(r4,0)
bne(WATER)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,4]) # move color to right
b(WATER)
label(TEST_RIGHT2)
ldrh(r4,[r3,4]) # r4 = right dest color
cmp(r4,0)
bne(TEST_LEFT2)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,4]) # move color to right
b(WATER)
label(TEST_LEFT2)
ldrh(r4,[r3,0]) # r4 = left dest color
cmp(r4,0)
bne(WATER)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,0]) # move color to left
b(WATER)
label(WATER_DONE)
sub(r1,1)
beq(EXIT)
b(LOOP_Y)
label(EXIT)
def core1():
global DONE,screen,RIGHT
#print(hex(water_asm(screen)))
#exit()
i=0
while i<150:
i+=1
gticks=ticks_us()
if i==50:
screen.fill_rect(randint(0,220),0,20,20,0xff) #0x7c02)
if i==100:
screen.fill_rect(randint(0,220),0,20,20,0xff00) #0x7c02)
i=0
screen.pixel(randint(0,240),0,0xff00)
screen.pixel(randint(90,95),0,0xff)
RIGHT=True
water_lasm(screen)
#if i==25 or i==50 or i==75 or i==99:
tft.blit_buffer(screen, 0, 0, MAXSCREEN_X, MAXSCREEN_Y)
fps=1_000_000//ticks_diff(ticks_us(), gticks)
print(fps)
DONE=True
@micropython.viper
def resize():
screen_addr=ptr16(display_buffer)
text_addr=ptr16(text_buffer)
offset = 80*MAXSCREEN_X+10
for y in range(8):
for x in range(60):
color=text_addr[y*80+x]
for ly in range(5):
for lx in range(5):
screen_addr[(ly+(5*y))*MAXSCREEN_X+(4*x)+lx+offset]=color
if __name__=='__main__':
spi = SPI(1, baudrate=80_000_000, sck=Pin(10), mosi=Pin(11))
tft = gc9a01.GC9A01(
spi,
240,
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)
tft.inversion_mode(True)
bl_ctrl(100)
sleep(0.5)
screen=framebuf.FrameBuffer(display_buffer, MAXSCREEN_X , MAXSCREEN_Y, framebuf.RGB565)
txt=framebuf.FrameBuffer(text_buffer, 80 , 8, framebuf.RGB565)
txt.text('PI PICO',0,0,0xffff)
resize()
#blit_image_file('floor.bin',32,32*8) # width, height
gticks=ticks_us()
#wdt = WDT(timeout=8300) # Watchdog timer reset
#blocks()
#tft.blit_buffer(screen, 0, 0, MAXSCREEN_X, MAXSCREEN_Y)
#exit()
#screen.fill(0xff00)
screen.fill_rect(0,200,239,239,0xff00)
#screen.line(0,50,240,50,0xffff)
_thread.start_new_thread(core1, ())
while not DONE:
if RIGHT:
RIGHT=False
water_rasm(screen)
exit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment