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.

125 lines
3.8 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(), 0.5 + random.random() / 2, 1)
class Twister:
def __init__(self, worldsize):
self.worldsize = worldsize
self.cycletime = 1.3
self.sat = 0.5 + random.random() / 2
self.hues = [random.random()]
self.hues += [ self.hues[0] + (i+1) * 0.25 for i in range(3) ]
random.shuffle(self.hues)
self.width = worldsize.x // 2.9
def update(self, t, dt):
# inspired by https://www.lexaloffle.com/bbs/?tid=3050
self.rows = []
a0 = t * math.pi / self.cycletime
while len(self.rows) < self.worldsize.y:
y = len(self.rows)
a = a0 - y * math.pi / self.worldsize.y \
* (math.sin(t * math.pi / 10) * 0.7)
ot1 = t * math.pi / 5
ot2 = y * math.pi / (self.worldsize.y * 2)
offs = self.worldsize.x / 2 + math.sin(ot1 + ot2) * self.width / 2
x1 = int(round(offs + self.width * math.sin(a)))
x2 = int(round(offs + self.width * math.sin(a+0.5*math.pi)))
x3 = int(round(offs + self.width * math.sin(a+math.pi)))
x4 = int(round(offs + self.width * math.sin(a+1.5*math.pi)))
row = []
for i, (start, end) in enumerate([(x1, x2), (x2, x3),
(x3, x4), (x4, x1)]):
if start < end:
row += [(x, i, (x - start) / (end - start - 1))
for x in range(start, end - 1)]
self.rows.append(row)
def draw(self, frame):
for y, line in enumerate(self.rows):
for point in line:
x, i, j = point
val = 1 - math.sin(j * math.pi) / 2.3
color = colorsys.hsv_to_rgb(self.hues[i], self.sat, val)
try:
frame.setPixel(x, 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)
twister = Twister(Point(WIDTH, HEIGHT))
t = 0
dt = args.delay / 1000
while t < args.time:
t += dt
frame = blup.animation.AnimationFrame(dim, args.delay)
twister.update(t, dt)
twister.draw(frame)
anim.addFrame(frame)
blup.writebml.writeBml(anim, args.output_file)