diff --git a/generators/dlines.py b/generators/dlines.py new file mode 100755 index 0000000..e2db520 --- /dev/null +++ b/generators/dlines.py @@ -0,0 +1,141 @@ +#!/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)