You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
4.2 KiB
142 lines
4.2 KiB
7 years ago
|
#!/usr/bin/env python3
|
||
|
|
||
|
import sys
|
||
|
import random
|
||
|
import math
|
||
|
import argparse
|
||
|
import collections
|
||
|
import blup.frame
|
||
|
import blup.output
|
||
|
import blup.animation
|
||
|
import blup.writebml
|
||
|
import colorsys
|
||
|
import functools
|
||
|
|
||
|
|
||
|
WIDTH = 22
|
||
|
HEIGHT = 16
|
||
|
DEPTH = 256
|
||
|
|
||
|
|
||
|
class Point(collections.namedtuple('Point', ['x', 'y'])):
|
||
|
def __add__(self, other):
|
||
|
return Point(self.x + other.x, self.y + other.y)
|
||
|
def __sub__(self, other):
|
||
|
return Point(self.x - other.x, self.y - other.y)
|
||
|
@property
|
||
|
def len(self):
|
||
|
return math.sqrt(self.x**2 + self.y**2)
|
||
|
|
||
|
|
||
|
class PointLenOrder:
|
||
|
def __init__(self, value):
|
||
|
self.value = value
|
||
|
def __eq__(self, other):
|
||
|
return other.value.len == self.value.len
|
||
|
def __lt__(self, other):
|
||
|
return other.value.len < self.value.len
|
||
|
|
||
|
|
||
|
DIRECTIONS = [ Point(x, y) for x in [-1, 1] for y in [-1, 1] ]
|
||
|
|
||
|
|
||
|
def convert_color(c):
|
||
|
return list(map(lambda x: int(round(x*(DEPTH-1))), c))
|
||
|
|
||
|
|
||
|
def get_random_color():
|
||
|
return colorsys.hsv_to_rgb(random.random(), 0.5 + random.random() / 2, 1)
|
||
|
|
||
|
|
||
|
class Line:
|
||
|
def __init__(self, worldsize):
|
||
|
self.worldsize = worldsize
|
||
|
self.line = [Point(random.randint(0, worldsize.x),
|
||
|
random.randint(0, worldsize.y))]
|
||
|
self.slen = 1
|
||
|
self.dir = random.choice(DIRECTIONS)
|
||
|
self.color = get_random_color()
|
||
|
diaglen = int(math.sqrt(worldsize.x**2 + worldsize.y**2))
|
||
|
self.maxlen = random.randint(diaglen, diaglen * 3)
|
||
|
self.fadeout_time = 2 + random.random() * 2
|
||
|
self.fadeout_remaining = None
|
||
|
self.finished = False
|
||
|
|
||
|
def check_bounds(self, p):
|
||
|
return p.x < self.worldsize.x and p.x >= 0 \
|
||
|
and p.y < self.worldsize.y and p.y >= 0
|
||
|
|
||
|
def update(self, t, dt):
|
||
|
if len(self.line) < self.maxlen:
|
||
|
if self.slen >= 3 and random.random() < 0.4:
|
||
|
dirs = list(DIRECTIONS)
|
||
|
dirs.remove(self.line[-1] - self.line[-2])
|
||
|
if self.check_bounds(self.line[-1]):
|
||
|
newp = None
|
||
|
while newp is None or newp == self.line[-2]:
|
||
|
self.dir = random.choice(dirs)
|
||
|
newp = self.line[-1] + self.dir
|
||
|
else:
|
||
|
dirs.sort(key=lambda d: ((self.line[-1]+d) - Point(0, 0)).len)
|
||
|
self.dir = dirs[0]
|
||
|
self.slen = 1
|
||
|
else:
|
||
|
self.slen += 1
|
||
|
self.line.append(self.line[-1] + self.dir)
|
||
|
else:
|
||
|
if self.fadeout_remaining is None:
|
||
|
self.fadeout_remaining = self.fadeout_time
|
||
|
elif self.fadeout_remaining <= 0:
|
||
|
self.finished = True
|
||
|
else:
|
||
|
self.fadeout_remaining -= dt
|
||
|
|
||
|
def draw(self, frame):
|
||
|
if self.fadeout_remaining is not None:
|
||
|
if self.fadeout_remaining > 0:
|
||
|
h, s, v = colorsys.rgb_to_hsv(*self.color)
|
||
|
v = v * (self.fadeout_remaining / self.fadeout_time)
|
||
|
color = colorsys.hsv_to_rgb(h, s, v)
|
||
|
else:
|
||
|
color = (0, 0, 0)
|
||
|
else:
|
||
|
color = self.color
|
||
|
for p in self.line:
|
||
|
if self.check_bounds(p):
|
||
|
frame.setPixel(p.x, p.y, convert_color(color))
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
parser = argparse.ArgumentParser(description='Generate animations')
|
||
|
parser.add_argument('-d', '--delay', type=int, default=50)
|
||
|
parser.add_argument('-t', '--time', type=int, default=15)
|
||
|
parser.add_argument('output_file')
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
dim = blup.frame.FrameDimension(WIDTH, HEIGHT, DEPTH, 3)
|
||
|
anim = blup.animation.Animation(dim)
|
||
|
anim.tags['description'] = ' '.join(sys.argv)
|
||
|
|
||
|
|
||
|
lines = [Line(Point(WIDTH, HEIGHT))]
|
||
|
t = 0
|
||
|
dt = args.delay / 1000
|
||
|
while t < args.time:
|
||
|
t += dt
|
||
|
frame = blup.animation.AnimationFrame(dim, args.delay)
|
||
|
|
||
|
for l in lines:
|
||
|
l.update(t, dt)
|
||
|
l.draw(frame)
|
||
|
|
||
|
if lines[-1].fadeout_remaining is not None:
|
||
|
lines.append(Line(Point(WIDTH, HEIGHT)))
|
||
|
|
||
|
for l in lines:
|
||
|
if l.finished:
|
||
|
lines.remove(l)
|
||
|
|
||
|
anim.addFrame(frame)
|
||
|
|
||
|
blup.writebml.writeBml(anim, args.output_file)
|