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.

140 lines
4.2 KiB

#!/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(), 0.5 + random.random() / 2, 1)
class BlinkingCheckerboard:
def __init__(self, size, fieldsize, h, num_fields, rounds):
self.size, self.fieldsize, self.h, self.num_fields, self.rounds = \
size, fieldsize, h, num_fields, rounds
self.roundtime = 0.5
self.fieldpoints = [
Point(random.randint(0, WIDTH-1), random.randint(0, HEIGHT-1))
]
xm = self.fieldpoints[-1].x % (fieldsize * 2)
ym = self.fieldpoints[-1].y % (fieldsize * 2)
while len(self.fieldpoints) < self.num_fields:
p = random.choice(self.fieldpoints)
o = Point(random.randint(-2, 2), random.randint(-2, 2))
if abs(o.x) + abs(o.y) != 2:
continue
p += o * fieldsize
if p.x < 0 or p.y < 0 or p.x >= size.x or p.y > size.y:
continue
if p not in self.fieldpoints:
self.fieldpoints.append(p)
self.done = False
def update(self, t, dt):
r = t / self.roundtime
if r >= self.rounds + 1:
self.done = True
self.fieldvals = [0] * self.num_fields
else:
self.fieldvals = []
for i in range(self.num_fields):
offs = i / (self.num_fields - 1) * 2 * math.pi
pos = 2 * math.pi * r
self.fieldvals.append(max(math.sin(offs + pos), 0))
if r > self.rounds and r < self.rounds + 1:
if self.fieldvals[-1] < 0.01:
self.fieldvals[-1] = 0
def draw(self, frame):
for i, f in enumerate(self.fieldpoints):
color = colorsys.hsv_to_rgb(self.h, 1, self.fieldvals[i])
for x in range(self.fieldsize):
for y in range(self.fieldsize):
try:
p = f + Point(x, y)
frame.setPixel(p.x, p.y, convert_color(color))
except ValueError:
pass
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)
t = 0
dt = args.delay / 1000
tt = 0
bc = None
while t < args.time or not bc.done:
t += dt
tt += dt
frame = blup.animation.AnimationFrame(dim, args.delay)
if (bc is None or bc.done) and t < args.time:
tt = 0
bc = BlinkingCheckerboard(
Point(WIDTH, HEIGHT),
2,
random.random(),
random.randint(13, 23),
random.randint(3, 5)
)
bc.update(tt, dt)
bc.draw(frame)
anim.addFrame(frame)
blup.writebml.writeBml(anim, args.output_file)