diff --git a/snowflakes.py b/snowflakes.py new file mode 100755 index 0000000..2f08c62 --- /dev/null +++ b/snowflakes.py @@ -0,0 +1,161 @@ +#!/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