Skip to content

Instantly share code, notes, and snippets.

@samneggs
Created January 2, 2022 02:09
Show Gist options
  • Save samneggs/dc14a35497f549b19cfe82f308f32c6b to your computer and use it in GitHub Desktop.
Save samneggs/dc14a35497f549b19cfe82f308f32c6b to your computer and use it in GitHub Desktop.
Plane Deformations with texture bitmaps - Pi Pico in MicroPython
# Based on routines by Inigo Quilez
# https://iquilezles.org/
from LCD_3inch5 import LCD_3inch5
import framebuf
import math
from time import sleep_ms, sleep_us, ticks_diff, ticks_us, sleep
from micropython import const
import array
from usys import exit
import gc
SCREEN_HEIGHT = const(70) #70
SCREEN_WIDTH = const(SCREEN_HEIGHT*3)
TEXTURE_HEIGHT = const(47) #75
TEXTURE_WIDTH = const(90) #75
# blit_image_file borrowed from Stewart Watkiss
# http://www.penguintutor.com/programming/picodisplayanimations
def blit_image_file(filename,width,height,cw,ch): # file width, file height, char width, char height
#global display_buffer,display_buffer2,screen
display_buffer = bytearray(cw*ch*2) #(width * height * 2)
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
buffer2[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()
#lcd.show_xy(0,0,TEXTURE_WIDTH-1,TEXTURE_HEIGHT-1,buffer2)
#sleep(5)
return
def init_texture():
for i in range(0,TEXTURE_HEIGHT):
texture.line(0,i,TEXTURE_WIDTH-1,i,color_l2[i*2+32])
#screen.blit(texture,0,0)
lcd.show_xy(0,0,TEXTURE_WIDTH-1,TEXTURE_HEIGHT-1,texture)
@micropython.viper
def render_texture():
screen_addr=ptr16(screen)
texture_addr=ptr16(texture)
for j in range(0,SCREEN_HEIGHT):
for i in range(0,SCREEN_WIDTH):
screen_addr[SCREEN_WIDTH*j+i] = texture_addr[TEXTURE_WIDTH*(j%(TEXTURE_HEIGHT-1)) + (i%(TEXTURE_WIDTH-1)) ]
lcd.show_xy(0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1,screen)
def createLUT():
for j in range(0,SCREEN_HEIGHT):
for i in range(SCREEN_WIDTH):
x = -1.00 + 2.00*i/SCREEN_WIDTH
y = -1.00 + 2.00*j/(SCREEN_HEIGHT+0)
d = math.sqrt( x*x + y*y )
a = math.atan2( y, x )
#print(i,x,y,d,a)
#print(int((x+1)*100))
#lcd.draw_point(i,int((a+3)*100),lcd.RED)
# magic formulas here
if y!=0:
#u=1/d/2 # messy circles
#v=1/d/2
#u = math.cos( a )/d # rotating magnet poles
#v = math.sin( a )/d
#u = x*math.cos(2*d) - y*math.sin(2*d) # groovy swirls
#v = y*math.cos(2*d) + x*math.sin(2*d)
#u = 0.3/(d+0.5*x) # spinning pinwheel
#v = 3*a/math.pi
#u = 0.02*y+0.03*math.cos(a*3)/(d/2) # nice center flower
#v = 0.02*x+0.03*math.sin(a*3)/(d/2)
#u = 0.1*x/(0.11+(d/2)*0.5) # scrolling bent horizon
#v = 0.1*y/(0.11+(d/2)*0.5)
#u = 0.5*a/math.pi # pulsating circles
#v = math.sin(7*d/2)
#u = d/2*math.cos(a+d/2) # swooshing wave
#v = d/2*math.sin(a+d/2)
#u = 1/(d/2+0.5+0.5*math.sin(5*a)) # spinning flower
#v = a*3/math.pi
u = x/abs(y) # 3d room
v = 1/abs(y)
mLUT.append((int(TEXTURE_WIDTH*u)) % (TEXTURE_WIDTH-1))
mLUT.append((int(TEXTURE_HEIGHT*v)) % (TEXTURE_HEIGHT-1))
@micropython.viper
def renderDeformation():
gticks=ticks_us()
screen_addr=ptr16(screen)
texture_addr=ptr16(texture)
mLUT_addr=ptr8(mLUT)
for itime in range(200): #(0,100,1):
h=0
for k in range(3): #3
for j in range(0,SCREEN_HEIGHT-3,3):
for i in range(0,SCREEN_WIDTH,3):
o = SCREEN_WIDTH*h + i
u = mLUT_addr[ 2*o+0 ] + itime
v = mLUT_addr[ 2*o+1 ] + itime
#color = texture_addr[TEXTURE_WIDTH*(j%(TEXTURE_HEIGHT-1)) + (i%(TEXTURE_WIDTH-1))]
color = texture_addr[TEXTURE_WIDTH*(v%(TEXTURE_HEIGHT-1)) + (u%(TEXTURE_WIDTH-1)) ]
screen_addr[SCREEN_WIDTH*j+i] = color
screen_addr[SCREEN_WIDTH*j+i+1] = color
screen_addr[SCREEN_WIDTH*j+i+2] = color
screen_addr[SCREEN_WIDTH*(j+1)+i] = color
screen_addr[SCREEN_WIDTH*(j+1)+i+1] = color
screen_addr[SCREEN_WIDTH*(j+1)+i+2] = color
screen_addr[SCREEN_WIDTH*(j+2)+i] = color
screen_addr[SCREEN_WIDTH*(j+2)+i+1] = color
screen_addr[SCREEN_WIDTH*(j+2)+i+2] = color
h+=1
lcd.show_xy(0,(SCREEN_HEIGHT-1)*k,SCREEN_WIDTH-1,(SCREEN_HEIGHT*(k+1))-2,screen)
delta = ticks_diff(ticks_us(), gticks)
#FPS=(1_000_000//delta)
print(delta)
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
if __name__=='__main__':
lcd = LCD_3inch5()
lcd.bl_ctrl(50)
lcd.Fill(lcd.BLACK)
buffer=bytearray(SCREEN_WIDTH*SCREEN_HEIGHT*2)
screen=framebuf.FrameBuffer(buffer,SCREEN_WIDTH,SCREEN_HEIGHT,framebuf.RGB565)
buffer2=bytearray(TEXTURE_WIDTH*TEXTURE_HEIGHT*2)
texture=framebuf.FrameBuffer(buffer2,TEXTURE_WIDTH,TEXTURE_HEIGHT,framebuf.RGB565)
blit_image_file("wall.bin",90,47,90,47) #wall
color_l2 = array.array('H', [])
fade(lcd.BLACK,lcd.BLUE)
fade(lcd.BLUE,lcd.GREEN)
fade(lcd.GREEN,lcd.YELLOW)
fade(lcd.YELLOW,lcd.ORANGE)
fade(lcd.ORANGE,lcd.RED)
fade(lcd.RED,lcd.ORANGE)
#init_texture()
render_texture()
mLUT = array.array('b',())
createLUT()
gc.collect()
print(gc.mem_free())
renderDeformation()
lcd.bl_ctrl(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment