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.
115 lines
3.2 KiB
115 lines
3.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
|
||
|
|
||
|
|
||
|
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)
|
||
|
def __mul__(self, other):
|
||
|
if isinstance(other, Point):
|
||
|
raise Exception('not implemented')
|
||
|
else:
|
||
|
return Point(self.x * other, self.y * other)
|
||
|
def __truediv__(self, other):
|
||
|
if isinstance(other, Point):
|
||
|
raise ValueError()
|
||
|
else:
|
||
|
return self * (1/other)
|
||
|
@property
|
||
|
def len(self):
|
||
|
return math.sqrt(self.x**2 + self.y**2)
|
||
|
@property
|
||
|
def n(self):
|
||
|
n = Point(self.y, -self.x)
|
||
|
return n / n.len
|
||
|
@property
|
||
|
def intp(self):
|
||
|
return Point(int(round(self.x)), int(round(self.y)))
|
||
|
|
||
|
|
||
|
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(), 1, 1)
|
||
|
|
||
|
|
||
|
class Disc:
|
||
|
def __init__(self, worldsize, hue):
|
||
|
self.worldsize = worldsize
|
||
|
self.pos = Point(random.randint(0, worldsize.x - 1),
|
||
|
random.randint(0, worldsize.y - 1))
|
||
|
self.hue = hue
|
||
|
self.r = 1
|
||
|
self.speed = min(worldsize.x, worldsize.y) / 2
|
||
|
self.done = False
|
||
|
|
||
|
def update(self, t, dt):
|
||
|
self.r += self.speed * dt
|
||
|
if self.r > max(self.worldsize.x, self.worldsize.y):
|
||
|
self.done = True
|
||
|
|
||
|
def draw(self, frame):
|
||
|
color = colorsys.hsv_to_rgb(self.hue, 1, 1)
|
||
|
for x in range(self.worldsize.x):
|
||
|
for y in range(self.worldsize.y):
|
||
|
p = Point(x, y)
|
||
|
if (p - self.pos).len < self.r:
|
||
|
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)
|
||
|
|
||
|
discs = []
|
||
|
t = 0
|
||
|
dt = args.delay / 1000
|
||
|
while t < args.time:
|
||
|
t += dt
|
||
|
frame = blup.animation.AnimationFrame(dim, args.delay)
|
||
|
|
||
|
if len(discs) == 0 or discs[-1].r > min(WIDTH, HEIGHT) / 2:
|
||
|
hue = random.random()
|
||
|
if len(discs) > 0:
|
||
|
l = lambda d: hue - d.hue if d.hue < hue else d.hue - hue
|
||
|
while not 0.2 < sorted(map(l, discs))[0] < 0.8:
|
||
|
hue = random.random()
|
||
|
discs.append(Disc(Point(WIDTH, HEIGHT), hue))
|
||
|
|
||
|
for d in discs:
|
||
|
d.update(t, dt)
|
||
|
d.draw(frame)
|
||
|
|
||
|
if len(discs) > 2 and discs[0].done and discs[1].done:
|
||
|
del discs[0]
|
||
|
|
||
|
anim.addFrame(frame)
|
||
|
|
||
|
blup.writebml.writeBml(anim, args.output_file)
|