162 lines
3.3 KiB
Python
Executable file
162 lines
3.3 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
import sk6812_multistrip as sk6812
|
|
import time
|
|
import math
|
|
import sys
|
|
import random
|
|
|
|
s = sk6812.SK6812(sys.argv[1], 2703)
|
|
|
|
phase = 0
|
|
nled = 16
|
|
nstrip = 8
|
|
|
|
interval = 1.0/60
|
|
|
|
#scale = 0.15
|
|
scale = 0.5
|
|
|
|
strip = 0
|
|
|
|
tiltphase = 0
|
|
|
|
#phase_speeds = [13, 23, 42, 5]
|
|
#phase_speeds = [37, 41, 43, 47]
|
|
phase_speeds = [701, 709, 719, 727]
|
|
|
|
class Framebuffer:
|
|
def __init__(self):
|
|
self.clear()
|
|
|
|
def clear(self):
|
|
self.r = [0] * (nstrip * nled)
|
|
self.g = [0] * (nstrip * nled)
|
|
self.b = [0] * (nstrip * nled)
|
|
self.w = [0] * (nstrip * nled)
|
|
|
|
def setpixel(self, strip, led, r, g, b, w):
|
|
idx = strip * nled + led
|
|
self.r[idx] = r
|
|
self.g[idx] = g
|
|
self.b[idx] = b
|
|
self.w[idx] = w
|
|
|
|
def addtopixel(self, strip, led, r, g, b, w):
|
|
idx = strip * nled + led
|
|
self.r[idx] += r
|
|
self.g[idx] += g
|
|
self.b[idx] += b
|
|
self.w[idx] += w
|
|
|
|
def render(self):
|
|
for strip in range(nstrip):
|
|
for led in range(nled):
|
|
idx = strip * nled + led
|
|
s.set_color(strip, led,
|
|
self.r[idx],
|
|
self.g[idx],
|
|
self.b[idx],
|
|
self.w[idx])
|
|
|
|
class Snowflake:
|
|
def __init__(self):
|
|
self.phase = random.random() * 2 * math.pi
|
|
self.frequency = 2*math.pi * 1
|
|
self.speed = random.random() * 0.1 + 0.05
|
|
|
|
self.radius = 1.1
|
|
self.radiussq = self.radius**2
|
|
|
|
self.pos_strip = self.base_pos_strip = random.randint(0, nstrip-1)
|
|
self.pos_led = nled-1+self.radius
|
|
|
|
def move(self):
|
|
self.phase += self.frequency * interval
|
|
self.pos_strip = self.base_pos_strip + 1 * math.sin(self.phase)
|
|
|
|
self.pos_led -= 0.1
|
|
|
|
def render(self, framebuffer):
|
|
for strip in range(int(math.floor(self.pos_strip-self.radius)), int(math.ceil(self.pos_strip+self.radius))):
|
|
for led in range(int(math.floor(self.pos_led-self.radius)), int(math.ceil(self.pos_led+self.radius))):
|
|
if led < 0 or led >= nled:
|
|
continue
|
|
|
|
distsq = (strip - self.pos_strip)**2 + (led - self.pos_led)**2
|
|
|
|
brightness = 1 - distsq / self.radiussq
|
|
if brightness < 0:
|
|
continue # brightness 0 -> no effect -> save some calculations
|
|
|
|
norm_strip = strip
|
|
while norm_strip < 0:
|
|
norm_strip += nstrip
|
|
while norm_strip >= nstrip:
|
|
norm_strip -= nstrip
|
|
|
|
framebuffer.addtopixel(norm_strip, led, 0, 0, int(32*brightness), int(48*brightness))
|
|
|
|
def has_fallen(self):
|
|
return self.pos_led < -self.radius
|
|
|
|
snowflakes = []
|
|
framebuffer = Framebuffer()
|
|
|
|
frame = 0
|
|
|
|
snowlevel = [0] * nstrip
|
|
|
|
while True:
|
|
# garbage collection
|
|
if True: #frame % 10 == 0:
|
|
visible_snowflakes = []
|
|
for flake in snowflakes:
|
|
if not flake.has_fallen():
|
|
visible_snowflakes.append(flake)
|
|
else:
|
|
idx = int(flake.base_pos_strip)
|
|
if idx < 0:
|
|
idx += nstrip
|
|
elif idx >= nstrip:
|
|
idx -= nstrip
|
|
|
|
snowlevel[idx] += 0.2
|
|
|
|
snowflakes = visible_snowflakes
|
|
|
|
# spawn new flakes
|
|
if random.random() < 0.1:
|
|
snowflakes.append(Snowflake())
|
|
|
|
framebuffer.clear()
|
|
|
|
# move and render the flakes
|
|
for flake in snowflakes:
|
|
flake.move()
|
|
flake.render(framebuffer)
|
|
|
|
# add snow on the ground
|
|
for strip in range(nstrip):
|
|
led = 0
|
|
level = snowlevel[strip]
|
|
while level > 0:
|
|
if level >= 1:
|
|
brightness = 1
|
|
else:
|
|
brightness = level
|
|
|
|
framebuffer.addtopixel(strip, led, 0, int(8*brightness), int(32*brightness), int(12*brightness))
|
|
|
|
level -= 1
|
|
led += 1
|
|
|
|
snowlevel[strip] *= 0.999
|
|
|
|
framebuffer.render()
|
|
|
|
s.commit()
|
|
|
|
time.sleep(interval)
|
|
frame += 1
|