Skip to content

Instantly share code, notes, and snippets.

@samneggs
Created January 8, 2022 06:11
Show Gist options
  • Save samneggs/0b3890eaf219e24c3676fd7861de64e4 to your computer and use it in GitHub Desktop.
Save samneggs/0b3890eaf219e24c3676fd7861de64e4 to your computer and use it in GitHub Desktop.
Pseudo Perlin noise mapped onto 3D matrix in MicroPython
from LCD_3inch5 import LCD_3inch5
from machine import Pin
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 math import sin,cos,pi, radians
MAXSCREEN_X = const(240)
MAXSCREEN_Y = const(240)
GRID_SIZE = const(10)
GRID_POINTS = const(25)
NUM_POINTS = const(GRID_POINTS*GRID_POINTS)
TEXTURE_HEIGHT = const(30) #47
TEXTURE_WIDTH = const(200)# 90
SCALE = const(14)
xcoord=array.array('h', 0 for _ in range(NUM_POINTS))
ycoord=array.array('h', 0 for _ in range(NUM_POINTS))
zcoord=array.array('h', 0 for _ in range(NUM_POINTS))
# blit_image_file borrowed from Stewart Watkiss
# http://www.penguintutor.com/programming/picodisplayanimations
def blit_image_file(buf,filename,width,height,cw,ch): # file width, file height, char width, char height
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
buf[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()
return
@micropython.viper
def init_arry(width:int,height:int,seed_arry):
seed_addr=ptr16(seed_arry)
for i in range(width*height):
seed_addr[i] = int(randint(0,0xffff))
@micropython.viper
def init_matrix(s:int,s2:int):
texture_addr=ptr16(texture)
xc=ptr16(xcoord)
yc=ptr16(ycoord)
zc=ptr16(zcoord)
i=0
for y in range(0,GRID_POINTS):
for x in range(0,GRID_POINTS):
h = texture_addr[TEXTURE_WIDTH*((0+y)%(TEXTURE_HEIGHT-1)) + ((s+x)%(TEXTURE_WIDTH-1))]>>12
xc[i]=x*GRID_SIZE # sin(radians(x*s))*10) # int((x*GRID_SIZE)+sin(radians(y*s))*30)
yc[i]=20+y*GRID_SIZE #(y*GRID_SIZE)#*y//2
zc[i]=h+y*s2//20 # h+y*s//20 int( sin(radians(y*s))*10+cos(radians(x*s))*10)
i+=1
# Based on Javidx9 C code
# OneLoneCoder.com - What Is Perlin Noise? Video: https://youtu.be/6-0UaeJBumA
@micropython.viper
def PerlinNoise2D(nWidth:int,nHeight:int,Seed_arry,nOctaves:int,fBias:int, Output_arry,s:int):
seed_addr=ptr16(Seed_arry)
output_addr=ptr16(Output_arry)
color_addr=ptr16(color_l2)
for x in range(nWidth):
for y in range(nHeight):
fNoise = 0
fScaleAcc = 0
fScale = s
for o in range(nOctaves):
nPitch = nWidth >> o
nSampleX1 = (x // nPitch) * nPitch
nSampleY1 = (y // nPitch) * nPitch
nSampleX2 = (nSampleX1 + nPitch) % nWidth
nSampleY2 = (nSampleY1 + nPitch) % nWidth
fBlendX = ((x - nSampleX1)<<SCALE) // nPitch
fBlendY = ((y - nSampleY1)<<SCALE) // nPitch
fSampleT = ((((1<<SCALE) - fBlendX) * seed_addr[nSampleY1 * nWidth + nSampleX1])>>SCALE) + ((fBlendX * seed_addr[nSampleY1 * nWidth + nSampleX2])>>SCALE)
fSampleB = ((((1<<SCALE) - fBlendX) * seed_addr[nSampleY2 * nWidth + nSampleX1])>>SCALE) + ((fBlendX * seed_addr[nSampleY2 * nWidth + nSampleX2])>>SCALE)
fScaleAcc += fScale
fNoise += ((((fBlendY * (fSampleB - fSampleT))>>SCALE) + fSampleT) // fScale)
fScale = fScale // fBias
output_addr[y * nWidth + x] = color_addr[(fNoise // fScaleAcc)]
def plot():
for i in range(0,NUM_POINTS-1):
x1=xcoord[i]+zcoord[i]
y1=ycoord[i]-zcoord[i]
x2=xcoord[i+1]+zcoord[i+1]
y2=ycoord[i+1]-zcoord[i+1]
if (i+1) % (GRID_POINTS) > 0 :
screen.line(x1,y1,x2,y2,color_l2[zcoord[i]])
if i < NUM_POINTS-GRID_POINTS :
x3=xcoord[i+GRID_POINTS]+zcoord[i+GRID_POINTS]
y3=ycoord[i+GRID_POINTS]-zcoord[i+GRID_POINTS]
screen.line(x1,y1,x3,y3,color_l2[zcoord[i]])
lcd.show_xy(0,0,MAXSCREEN_X-1,MAXSCREEN_Y-1,screen)
screen.fill(0)
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(100)
lcd.Fill(lcd.BLACK)
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.WHITE)
buffer1=bytearray(TEXTURE_WIDTH*TEXTURE_HEIGHT*2) # random
texture=bytearray(TEXTURE_WIDTH*TEXTURE_HEIGHT*2) # Perlin
texture_draw=framebuf.FrameBuffer(texture,TEXTURE_WIDTH,TEXTURE_HEIGHT,framebuf.RGB565)
init_arry(TEXTURE_WIDTH,TEXTURE_HEIGHT,buffer1)
lcd.show_xy(0,0,TEXTURE_WIDTH-1,TEXTURE_HEIGHT-1,buffer1)
PerlinNoise2D(TEXTURE_WIDTH,TEXTURE_HEIGHT,buffer1,6,1, texture,50)
texture_draw.fill_rect(0,0,60,10,0)
texture_draw.text('PI PICO',0,0,0xffff)
lcd.show_xy(MAXSCREEN_X,0,MAXSCREEN_X+TEXTURE_WIDTH-1,TEXTURE_HEIGHT-1,texture)
display_buffer=bytearray(MAXSCREEN_X * MAXSCREEN_Y * 2)
screen=framebuf.FrameBuffer(display_buffer, MAXSCREEN_X , MAXSCREEN_Y, framebuf.RGB565)
#texture=framebuf.FrameBuffer(buffer2,TEXTURE_WIDTH,TEXTURE_HEIGHT,framebuf.RGB565)
#blit_image_file(buffer2,"wall.bin",90,47,90,47)
while(1):
s2=0
for s in range(1,TEXTURE_WIDTH):
init_matrix(s,s2)
plot()
if s<TEXTURE_WIDTH//2:
s2+=1
else:
s2-=1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment