Compare commits
47 Commits
feature/ba
...
master
27 changed files with 2026 additions and 221 deletions
@ -0,0 +1,126 @@
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
import sys |
||||
import random |
||||
import argparse |
||||
import blup.frame |
||||
import blup.output |
||||
import blup.animation |
||||
import blup.writebml |
||||
import colorsys |
||||
|
||||
|
||||
WIDTH = 22 |
||||
HEIGHT = 16 |
||||
DEPTH = 256 |
||||
|
||||
|
||||
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) |
||||
|
||||
|
||||
def get_random_point(): |
||||
return (random.randint(0, WIDTH-1), random.randint(0, HEIGHT-1)) |
||||
|
||||
|
||||
def cap(x): |
||||
return min(1, max(0, x)) |
||||
|
||||
|
||||
def cyc(x): |
||||
while x < 0: |
||||
x += 1 |
||||
while x > 1: |
||||
x -= 1 |
||||
return x |
||||
|
||||
|
||||
class Point: |
||||
def __init__(self, pos, color, evolve): |
||||
self.pos = pos |
||||
self.color = color |
||||
self.neighbours = [] |
||||
h, s, v = colorsys.rgb_to_hsv(*color) |
||||
self.evolve = evolve |
||||
if 'h' in evolve: |
||||
h += (random.random()-.5) * 0.1 |
||||
if 's' in evolve: |
||||
s += (random.random()-.5) * 0.5 |
||||
if 'v' in evolve: |
||||
v += (random.random()-.5) * 0.5 |
||||
self.ncolor = colorsys.hsv_to_rgb(cyc(h), cap(s), cap(v)) |
||||
|
||||
def __eq__(self, other): |
||||
return self.pos == other.pos |
||||
|
||||
def __hash__(self): |
||||
return self.pos.__hash__() |
||||
|
||||
def get_neighbours(self): |
||||
for x in [-1, 0, 1]: |
||||
for y in [-1, 0, 1]: |
||||
n = (self.pos[0]+x, self.pos[1]+y) |
||||
if n[0] >= 0 and n[1] >= 0 and n[0] < WIDTH and \ |
||||
n[1] < HEIGHT and abs(x+y) < 2: |
||||
yield Point(n, self.ncolor, self.evolve) |
||||
|
||||
|
||||
class Blob: |
||||
def __init__(self, pos, color): |
||||
e = random.choice('hsv') |
||||
if random.random() > 0.8: |
||||
e += random.choice('hsv') |
||||
p = Point(pos, color, e) |
||||
self.points = set([p]) |
||||
self.candids = set(p.get_neighbours()) |
||||
self.completed = False |
||||
|
||||
def grow(self): |
||||
if len(self.candids) == 0: |
||||
self.completed = True |
||||
return |
||||
newp = random.sample(self.candids, 1)[0] |
||||
self.candids.remove(newp) |
||||
self.points.add(newp) |
||||
self.candids = self.candids.union(set(newp.get_neighbours()) - |
||||
self.points - self.candids) |
||||
|
||||
def draw(self, frame): |
||||
for p in self.points: |
||||
frame.setPixel(p.pos[0], p.pos[1], convert_color(p.color)) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
parser = argparse.ArgumentParser(description='Generate blob 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 |
||||
blobs = [Blob(get_random_point(), get_random_color())] |
||||
while t < args.time: |
||||
t += args.delay / 1000 |
||||
frame = blup.animation.AnimationFrame(dim, args.delay) |
||||
|
||||
for b in blobs: |
||||
for i in range(4): |
||||
b.grow() |
||||
b.draw(frame) |
||||
|
||||
if len(blobs[-1].points) > WIDTH*HEIGHT*0.6 and len(blobs) < 3: |
||||
blobs.append(Blob(get_random_point(), get_random_color())) |
||||
if len(blobs) >=2 and blobs[0].completed and blobs[1].completed: |
||||
blobs.remove(blobs[0]) |
||||
|
||||
anim.addFrame(frame) |
||||
|
||||
blup.writebml.writeBml(anim, args.output_file) |
@ -0,0 +1,140 @@
@@ -0,0 +1,140 @@
|
||||
#!/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) |
@ -0,0 +1,107 @@
@@ -0,0 +1,107 @@
|
||||
#!/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) |
||||
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 CurveFunction(): |
||||
def __init__(self, p1, p2): |
||||
self.p1, self.p2 = p1, p2 |
||||
d = p2 - p1 |
||||
self.pp = p1 + d/2 + d.n * (d.len * 0.8) |
||||
|
||||
def __call__(self, t): |
||||
ret = (self.p1 - self.pp*2 + self.p2) * t**2 |
||||
ret += (self.p1 * -2 + self.pp * 2) * t |
||||
ret += self.p1 |
||||
return ret |
||||
|
||||
|
||||
|
||||
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 |
||||
while t < args.time: |
||||
t += dt |
||||
|
||||
p1 = p2 = None |
||||
while p1 == p2 or (p1 - p2).len < max(WIDTH, HEIGHT) / 2: |
||||
p1 = Point(random.randint(0, WIDTH-1), random.randint(0, HEIGHT-1)) |
||||
p2 = Point(random.randint(0, WIDTH-1), random.randint(0, HEIGHT-1)) |
||||
cf = CurveFunction(p1, p2) |
||||
color = convert_color(get_random_color()) |
||||
tt = 0 |
||||
points = [] |
||||
while tt <= 1: |
||||
t += dt |
||||
tt += 0.025 |
||||
p = cf(tt).intp |
||||
points.append(p) |
||||
frame = blup.animation.AnimationFrame(dim, args.delay) |
||||
for p in points: |
||||
try: |
||||
frame.setPixel(p.x, p.y, color) |
||||
except ValueError: |
||||
pass |
||||
anim.addFrame(frame) |
||||
|
||||
blup.writebml.writeBml(anim, args.output_file) |
@ -0,0 +1,114 @@
@@ -0,0 +1,114 @@
|
||||
#!/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) |
@ -0,0 +1,141 @@
@@ -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) |
@ -0,0 +1,150 @@
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
import sys |
||||
import random |
||||
import argparse |
||||
import collections |
||||
import blup.frame |
||||
import blup.output |
||||
import blup.animation |
||||
import blup.writebml |
||||
import colorsys |
||||
|
||||
|
||||
WIDTH = 22 |
||||
HEIGHT = 16 |
||||
DEPTH = 256 |
||||
SMILEYSIZE = 5 |
||||
|
||||
Point = collections.namedtuple('Point', ['x', 'y']) |
||||
|
||||
|
||||
def convert_color(c): |
||||
return list(map(lambda x: int(round(x*(DEPTH-1))), c)) |
||||
|
||||
|
||||
def expand(somepoints, allpoints): |
||||
todo = set(somepoints) |
||||
ret = set(somepoints) |
||||
while len(todo) > 0: |
||||
p = todo.pop() |
||||
ret.add(p) |
||||
adj = { Point(p.x + x, p.y + y) for x in [-1,0,1] for y in [-1,0,1] \ |
||||
if abs(x) + abs(y) == 1 and p.x + x in range(0, SMILEYSIZE) \ |
||||
and p.y + y in range(0, SMILEYSIZE) } |
||||
adj = (allpoints - ret).intersection(adj) |
||||
todo = todo.union(adj) |
||||
return ret |
||||
|
||||
|
||||
def gen_face_shape(): |
||||
while True: |
||||
i = random.randint(0, 2**(SMILEYSIZE * (SMILEYSIZE//2 + 1))) |
||||
lpoints = { Point(x, y) for x in range(0, SMILEYSIZE // 2) \ |
||||
for y in range(SMILEYSIZE) \ |
||||
if i & 2**(x*SMILEYSIZE + y) > 0 } |
||||
mpoints = { Point(SMILEYSIZE//2, y) for y in range(SMILEYSIZE) \ |
||||
if i & 2**((SMILEYSIZE//2) * SMILEYSIZE + y) > 0 } |
||||
rpoints = { Point(SMILEYSIZE - x - 1, y) \ |
||||
for x in range(0, SMILEYSIZE // 2) \ |
||||
for y in range(SMILEYSIZE) \ |
||||
if i & 2**(x*SMILEYSIZE + y) > 0 } |
||||
points = set.union(lpoints, mpoints, rpoints) |
||||
|
||||
eyes = { p for p in points if p.y < SMILEYSIZE // 2 and \ |
||||
p.x != SMILEYSIZE // 2 } |
||||
nose = { p for p in points if p.y >= SMILEYSIZE // 3 and \ |
||||
p.y < SMILEYSIZE // 2 + 1 and p.x == SMILEYSIZE//2 } |
||||
mouth = { p for p in points if p.y > SMILEYSIZE // 2 } |
||||
|
||||
nose = expand(nose, points) |
||||
mouth = expand(mouth, points) |
||||
|
||||
face = True |
||||
if len(eyes.intersection(nose)) > 0: |
||||
face = False |
||||
if len(eyes.intersection(mouth)) > 0: |
||||
face = False |
||||
if len(nose.intersection(mouth)) > 0: |
||||
face = False |
||||
if len(points - eyes - nose - mouth) > 0: |
||||
face = False |
||||
if len(eyes) == 0: |
||||
face = False |
||||
if len(mouth) == 0: |
||||
face = False |
||||
if len(nose) > 0: |
||||
nosey = set(map(lambda p: p.y, nose)) |
||||
if min(nosey) < SMILEYSIZE//3: |
||||
face = False |
||||
|
||||
if face: |
||||
return points |
||||
|
||||
|
||||
class Face: |
||||
def __init__(self, pos): |
||||
self.pos = pos |
||||
self.shape = gen_face_shape() |
||||
self.lifetime = 0.7 |
||||
self.fadetime = 0.1 + random.random() / 10 |
||||
self.age = 0 |
||||
self.done = False |
||||
self.hue = random.random() |
||||
|
||||
def update(self, dt): |
||||
self.age += dt |
||||
if self.age > self.lifetime: |
||||
self.done = True |
||||
|
||||
def draw(self, frame): |
||||
if self.done: |
||||
return |
||||
if self.age < self.fadetime: |
||||
v = self.age / self.fadetime |
||||
elif self.age > self.lifetime - self.fadetime: |
||||
v = (self.lifetime-self.age) / self.fadetime |
||||
else: |
||||
v = 1 |
||||
for p in self.shape: |
||||
frame.setPixel( |
||||
p.x + self.pos.x, |
||||
p.y + self.pos.y, |
||||
convert_color(colorsys.hsv_to_rgb(self.hue, 1, v)) |
||||
) |
||||
|
||||
|
||||
def get_face_pos(): |
||||
x = random.randint(0, WIDTH - SMILEYSIZE) |
||||
y = random.randint(0, HEIGHT - SMILEYSIZE) |
||||
return Point(x, y) |
||||
|
||||
if __name__ == '__main__': |
||||
parser = argparse.ArgumentParser(description='Generate Face 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) |
||||
|
||||
f = Face(get_face_pos()) |
||||
t = 0 |
||||
dt = args.delay / 1000 |
||||
while f is not None: |
||||
t += dt |
||||
frame = blup.animation.AnimationFrame(dim, args.delay) |
||||
|
||||
f.update(dt) |
||||
f.draw(frame) |
||||
if f.done: |
||||
if t < args.time: |
||||
f = Face(get_face_pos()) |
||||
else: |
||||
f = None |
||||
|
||||
anim.addFrame(frame) |
||||
|
||||
blup.writebml.writeBml(anim, args.output_file) |
@ -0,0 +1,121 @@
@@ -0,0 +1,121 @@
|
||||
#!/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 Line: |
||||
def __init__(self, size): |
||||
self.size = size |
||||
r = random.choice([0, 1]) |
||||
s = random.choice([-1, 1]) |
||||
if r == 0: |
||||
self.pos = Point(size.x if s == -1 else 0, |
||||
random.randint(0, size.y - 1)) |
||||
else: |
||||
self.pos = Point(random.randint(0, size.x - 1), |
||||
size.y if s == -1 else 0) |
||||
self.dir = Point(s if r == 0 else 0, s if r == 1 else 0) |
||||
m = max(size.x, size.y) |
||||
self.length = random.randint(int(0.4 * m), int(1.1 * m)) |
||||
self.color = get_random_color() |
||||
self.speed = 10 |
||||
self.done = False |
||||
|
||||
def update(self, t, dt): |
||||
self.pos += self.dir * (dt * self.speed) |
||||
end = self.pos - self.dir * self.length |
||||
if self.dir.x > 0 and end.x > self.size.x \ |
||||
or self.dir.y > 0 and end.y > self.size.y \ |
||||
or self.dir.x < 0 and end.x < 0 \ |
||||
or self.dir.y < 0 and end.y < 0: |
||||
self.done = True |
||||
|
||||
def draw(self, frame): |
||||
if self.done: |
||||
return |
||||
for i in range(self.length): |
||||
p = self.pos.intp - self.dir * i |
||||
try: |
||||
frame.setPixel(p.x, p.y, convert_color(self.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) |
||||
|
||||
lines = [] |
||||
t = 0 |
||||
dt = args.delay / 1000 |
||||
while t < args.time or len(lines) > 0: |
||||
t += dt |
||||
frame = blup.animation.AnimationFrame(dim, args.delay) |
||||
|
||||
if len(lines) < 5 and t < args.time: |
||||
lines.append(Line(Point(WIDTH, HEIGHT))) |
||||
|
||||
for l in lines: |
||||
l.update(t, dt) |
||||
l.draw(frame) |
||||
lines = list(filter(lambda l: not l.done, lines)) |
||||
|
||||
anim.addFrame(frame) |
||||
|
||||
blup.writebml.writeBml(anim, args.output_file) |
@ -0,0 +1,222 @@
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
import sys |
||||
import random |
||||
import argparse |
||||
import collections |
||||
import blup.frame |
||||
import blup.output |
||||
import blup.animation |
||||
import blup.writebml |
||||
import colorsys |
||||
import math |
||||
|
||||
|
||||
WIDTH = 22 |
||||
HEIGHT = 16 |
||||
DEPTH = 256 |
||||
|
||||
_ALLSHAPES = [ |
||||
[[0, 1, 0, 1, 0], |
||||
[1, 1, 1, 1, 1], |
||||
[1, 1, 1, 1, 1], |
||||
[0, 1, 1, 1, 0], |
||||
[0, 0, 1, 0, 0]], |
||||
|
||||
[[1, 0, 0, 0, 1], |
||||
[0, 0, 1, 0, 0], |
||||
[0, 0, 1, 0, 0], |
||||
[1, 0, 0, 0, 1], |
||||
[0, 1, 1, 1, 0]], |
||||
|
||||
[[1, 0, 1, 0, 1], |
||||
[0, 1, 1, 1, 0], |
||||
[0, 1, 1, 1, 0], |
||||
[0, 1, 0, 1, 0], |
||||
[1, 1, 0, 1, 1]], |
||||
] |
||||
|
||||
|
||||
|
||||
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) |
||||
|
||||
ALLSHAPES = [] |
||||
for s in _ALLSHAPES: |
||||
ALLSHAPES.append(set()) |
||||
y = 0 |
||||
for l in s: |
||||
x = 0 |
||||
for i in l: |
||||
if i == 1: |
||||
ALLSHAPES[-1].add(Point(x, y)) |
||||
x += 1 |
||||
y += 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(), 1, 1) |
||||
|
||||
|
||||
class Shape: |
||||
def __init__(self, shape, pos, color): |
||||
self.shape, self.pos, self.color = shape, pos, color |
||||
self.period = 2 |
||||
self.fadetime = 0.5 + random.random() / 5 |
||||
self.t = random.random() * self.period |
||||
self.t = 0 |
||||
self.oldv = 1 |
||||
self.v = 1 |
||||
self.newshape = None |
||||
|
||||
def update(self, t, dt): |
||||
self.t += dt |
||||
if self.t > self.period: |
||||
t = self.t - self.period |
||||
if t >= self.fadetime: |
||||
self.v = 1 |
||||
self.t = random.random() * self.period |
||||
else: |
||||
self.v = math.cos(t * (math.pi / self.fadetime)) ** 2 |
||||
if (self.newshape is not None \ |
||||
and (self.oldv < self.v or self.v == 0)): |
||||
self.shape = self.newshape |
||||
self.color = self.newcolor |
||||
self.newshape = None |
||||
self.oldv = self.v |
||||
|
||||
def change_shape_and_color(self, newshape, newcolor): |
||||
self.newshape = newshape |
||||
self.newcolor = newcolor |
||||
self.t = self.period |
||||
|
||||
def draw(self, frame, origin=Point(0, 0)): |
||||
h, s, v = colorsys.rgb_to_hsv(*self.color) |
||||
for p in self.shape: |
||||
try: |
||||
pos = self.pos + p - origin |
||||
c = colorsys.hsv_to_rgb(h, s, v * self.v) |
||||
frame.setPixel(pos.x, pos.y, convert_color(c)) |
||||
except ValueError: |
||||
pass |
||||
|
||||
|
||||
class World: |
||||
def __init__(self, size, allshapes, gap=2): |
||||
self.size, self.allshapes, self.gap = size, allshapes, gap |
||||
self.shapes = {} |
||||
self.pos = Point(0, 0) |
||||
self.cycletime = 60 |
||||
self.curshape = random.choice(allshapes) |
||||
self.curcolor = get_random_color() |
||||
|
||||
self.shapesize = Point(0, 0) |
||||
for s in allshapes: |
||||
assert min(map(lambda p: p.x, s)) >= 0 |
||||
assert min(map(lambda p: p.y, s)) >= 0 |
||||
shapesize = Point( |
||||
max(map(lambda p: p.x, s)) + 1, |
||||
max(map(lambda p: p.y, s)) + 1, |
||||
) |
||||
if shapesize.x > self.shapesize.x: |
||||
self.shapesize = Point(shapesize.x, self.shapesize.y) |
||||
if shapesize.y > self.shapesize.y: |
||||
self.shapesize = Point(self.shapesize.x, shapesize.y) |
||||
print (self.shapesize) |
||||
|
||||
@property |
||||
def shape_space(self): |
||||
ret = set() |
||||
for x in range(self.size.x): |
||||
for y in range(self.size.y): |
||||
p = self.pos + Point(x, y) |
||||
if (p.x % (self.shapesize.x + self.gap) >= self.gap |
||||
and p.y % (self.shapesize.y + self.gap) >= self.gap): |
||||
ret.add(p) |
||||
return ret |
||||
|
||||
def get_shape_coverage(self, shape): |
||||
return { shape.pos + Point(x, y) for x in range(self.shapesize.x) \ |
||||
for y in range(self.shapesize.y) } |
||||
|
||||
def update(self, t, dt): |
||||
self.pos = Point( |
||||
int(math.sin((t * math.pi/self.cycletime)*4) * self.size.x), |
||||
int(math.cos((t * math.pi/self.cycletime)*5) * self.size.y) |
||||
) |
||||
|
||||
space = self.shape_space |
||||
for s in self.shapes.values(): |
||||
space -= self.get_shape_coverage(s) |
||||
while len(space) > 0: # and len(self.shapes) < 1: |
||||
print('...') |
||||
p = space.pop() |
||||
newpos = Point( |
||||
(p.x // (self.shapesize.x + self.gap)) \ |
||||
* (self.shapesize.x + self.gap) + self.gap, |
||||
(p.y // (self.shapesize.y + self.gap)) \ |
||||
* (self.shapesize.y + self.gap) + self.gap |
||||
) |
||||
print(p, newpos) |
||||
# TODO improve shape and color selection |
||||
newshape = Shape(self.curshape, newpos, self.curcolor) |
||||
assert newpos in self.get_shape_coverage(newshape) |
||||
print('covered', self.get_shape_coverage(newshape)) |
||||
print('space before', len(space)) |
||||
space -= self.get_shape_coverage(newshape) |
||||
print('space after ', len(space)) |
||||
assert newpos not in self.shapes |
||||
self.shapes[newpos] = newshape |
||||
print('new', len(self.shapes)) |
||||
#print(space) |
||||
|
||||
newshape = None |
||||
newcolor = None |
||||
if round(t*1000) % 3000 == 0: |
||||
newshape = random.choice(self.allshapes) |
||||
self.curshape = newshape |
||||
newcolor = get_random_color() |
||||
self.curcolor = newcolor |
||||
for s in self.shapes.values(): |
||||
if newshape is not None: |
||||
s.change_shape_and_color(newshape, newcolor) |
||||
s.update(t, dt) |
||||
|
||||
def draw(self, frame): |
||||
for s in self.shapes.values(): |
||||
s.draw(frame, self.pos) |
||||
|
||||
|
||||
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) |
||||
|
||||
w = World(Point(WIDTH, HEIGHT), ALLSHAPES) |
||||
t = 0 |
||||
dt = args.delay / 1000 |
||||
while t < args.time: |
||||
t += dt |
||||
frame = blup.animation.AnimationFrame(dim, args.delay) |
||||
|
||||
w.update(t, dt) |
||||
w.draw(frame) |
||||
|
||||
anim.addFrame(frame) |
||||
|
||||
blup.writebml.writeBml(anim, args.output_file) |
@ -0,0 +1,122 @@
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
import sys |
||||
import random |
||||
import numpy as np |
||||
import argparse |
||||
import blup.frame |
||||
import blup.output |
||||
import blup.animation |
||||
import blup.writebml |
||||
import colorsys |
||||
|
||||
|
||||
WIDTH = 22 |
||||
HEIGHT = 16 |
||||
DEPTH = 256 |
||||
|
||||
|
||||
def fill_trace(points): |
||||
for i in range(len(points)): |
||||
yield points[i] |
||||
if i == len(points)-1: |
||||
break |
||||
v = points[i+1] - points[i] |
||||
l = int(np.linalg.norm(v)) |
||||
for j in range(l): |
||||
yield points[i] + v * (j+1)/(l+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(), 1, 1) |
||||
|
||||
|
||||
class Orb: |
||||
def __init__(self, pos, speed, tracelen, color, tracecolor, boxsize): |
||||
self.pos = pos |
||||
self.speed = speed |
||||
self.tracelen = tracelen |
||||
self.color = color |
||||
self.tracecolor = tracecolor |
||||
self.boxsize = boxsize |
||||
self.trace = [] |
||||
|
||||
def update(self, dt): |
||||
newpos = self.pos + self.speed * dt |
||||
#newpos = self.pos |
||||
for dim in [0, 1]: |
||||
if newpos[dim] >= self.boxsize[dim] or newpos[dim] <= 0: |
||||
newpos[dim] = 0 if newpos[dim]<0 else self.boxsize[dim]-1 |
||||
self.speed[dim] *= -1 |
||||
self.speed += np.array([random.randint(-5, 6), random.randint(-5, 6)]) |
||||
self.trace.insert(0, self.pos) |
||||
self.trace = self.trace[:self.tracelen] |
||||
self.pos = newpos |
||||
|
||||
def draw(self, frame): |
||||
for i, p in enumerate(fill_trace([self.pos] + self.trace)): |
||||
f = (self.tracelen - i) / self.tracelen |
||||
try: |
||||
c = colorsys.rgb_to_hsv(*self.tracecolor) |
||||
s = 0.1 if random.random()>0.9 else c[1] |
||||
c = colorsys.hsv_to_rgb(c[0], s, c[2]*f) |
||||
frame.setPixel(int(p[0]), int(p[1]), convert_color(c)) |
||||
except ValueError: |
||||
pass |
||||
|
||||
offs = [ np.array([x,y]) for x in [-1,0,1] for y in [-1,0,1] ] |
||||
points = [] |
||||
for o in offs: |
||||
p = self.pos.astype('int') + o |
||||
if random.random() > 0.2 and not (p == np.array([0,0])).all(): |
||||
points.append(p) |
||||
for p in points: |
||||
try: |
||||
c = colorsys.rgb_to_hsv(*self.color) |
||||
c = colorsys.hsv_to_rgb(c[0], c[1], c[2]*0.2) |
||||
frame.setPixel(p[0], p[1], convert_color(c)) |
||||
except ValueError: |
||||
pass |
||||
|
||||
frame.setPixel(int(self.pos[0]), int(self.pos[1]), convert_color(self.color)) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
parser = argparse.ArgumentParser(description='Generate plasma animations') |
||||
parser.add_argument('-d', '--delay', type=int, default=50) |
||||
parser.add_argument('-t', '--time', type=int, default=15) |
||||
parser.add_argument('-n', '--num-orbs', type=int, default=2) |
||||
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) |
||||
|
||||
orbs = [] |
||||
for i in range(args.num_orbs): |
||||
orbs.append(Orb( |
||||
np.array([random.randint(0, WIDTH-1),random.randint(0, HEIGHT-1)]), |
||||
np.array([8,10]), |
||||
20, |
||||
get_random_color(), |
||||
get_random_color(), |
||||
np.array([WIDTH, HEIGHT]) |
||||
)) |
||||
|
||||
t = 0 |
||||
while t < args.time: |
||||
t += args.delay / 1000 |
||||
frame = blup.animation.AnimationFrame(dim, args.delay) |
||||
|
||||
for orb in orbs: |
||||
orb.update(args.delay / 1000) |
||||
orb.draw(frame) |
||||
|
||||
anim.addFrame(frame) |
||||
|
||||
blup.writebml.writeBml(anim, args.output_file) |
@ -0,0 +1,232 @@
@@ -0,0 +1,232 @@
|
||||
#!/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) |
||||
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 CurveFunction(): |
||||
def __init__(self, p1, p2): |
||||
self.p1, self.p2 = p1, p2 |
||||
d = p2 - p1 |
||||
self.pp = p1 + d/2 + d.n * (d.len * 0.8) |
||||
|
||||
def __call__(self, t): |
||||
ret = (self.p1 - self.pp*2 + self.p2) * t**2 |
||||
ret += (self.p1 * -2 + self.pp * 2) * t |
||||
ret += self.p1 |
||||
return ret |
||||
|
||||
|
||||
|
||||
class Box(): |
||||
def __init__(self, pos, size, hue, swaptime, content=None, |
||||
contentcolor=None): |
||||
self.pos, self.size, self.hue, self.content, self.contentcolor = \ |
||||
pos, size, hue, content, contentcolor |
||||
self.swaptime = swaptime |
||||
self.covered = False |
||||
self.swapstart = None |
||||
self.newpos = None |
||||
self.cf = None |
||||
self.colorcycletime = 1 |
||||
|
||||
def swap(self, other): |
||||
self.newpos = other.pos |
||||
other.newpos = self.pos |
||||
|
||||
def update(self, t, dt): |
||||
self.hue += 0.05 # dt / self.colorcycletime |
||||
if self.hue > 1: |
||||
self.hue -= 1 |
||||
if self.newpos is not None: |
||||
if self.cf is None: |
||||
self.cf = CurveFunction(self.pos, self.newpos) |
||||
self.swapstart = t |
||||
elif t - self.swapstart >= self.swaptime: |
||||
self.pos = self.newpos |
||||
self.newpos = None |
||||
self.cf = None |
||||
self.swapstart = None |
||||
else: |
||||
self.pos = (self.cf((t - self.swapstart) / self.swaptime)).intp |
||||
|
||||
def draw(self, frame): |
||||
if self.covered: |
||||
for x in range(self.size): |
||||
for y in range(self.size): |
||||
if x == 0 or x == self.size - 1 \ |
||||
or y == 0 or y == self.size -1: |
||||
color = (0.6, 0.6, 0.6) |
||||
else: |
||||
color = colorsys.hsv_to_rgb(self.hue, 1, 1) |
||||
try: |
||||
frame.setPixel(self.pos.x + x, self.pos.y + y, |
||||
convert_color(color)) |
||||
except ValueError: |
||||
pass |
||||
else: |
||||
if self.content is not None: |
||||
for p in self.content: |
||||
try: |
||||
frame.setPixel(self.pos.x + p.x + 1, |
||||
self.pos.y + p.y + 1, |
||||
convert_color(self.contentcolor)) |
||||
except ValueError: |
||||
pass |
||||
|
||||
|
||||
class Game(): |
||||
def __init__(self, size, boxsize, gap, content, contentcolor, swaptime): |
||||
self.swaptime = swaptime |
||||
self.boxes = [] |
||||
boxbase = Point((size.x - (2*boxsize + gap)) / 2, |
||||
(size.y - (2*boxsize + gap)) / 2) |
||||
self.n_boxes = 4 |
||||
for i in range(self.n_boxes): |
||||
boxpos = boxbase + Point( |
||||
(i % (self.n_boxes/2)) * (boxsize + gap), |
||||
(i // (self.n_boxes/2)) * (boxsize + gap) |
||||
) |
||||
self.boxes.append(Box( |
||||
boxpos.intp, |
||||
boxsize, |
||||
i * (1/self.n_boxes), |
||||
swaptime |
||||
)) |
||||
winner = random.randint(0, self.n_boxes - 1) |
||||
self.boxes[winner].content = content |
||||
self.boxes[winner].contentcolor = contentcolor |
||||
self.statetimes = [2, 1, 5, 2, 1, 2] |
||||
self.statestarts = [0] |
||||
for t in self.statetimes[:-1]: |
||||
self.statestarts.append(self.statestarts[-1] + t) |
||||
self.done = False |
||||
|
||||
def update(self, t, dt): |
||||
state = 0 |
||||
for i, st in enumerate(self.statestarts): |
||||
if st < t: |
||||
state = i |
||||
else: |
||||
break |
||||
state_t = t - self.statestarts[state] |
||||
|
||||
if state == 1 or state == 4: |
||||
for i, b in enumerate(self.boxes): |
||||
if state_t >= i * (self.statetimes[state] / self.n_boxes): |
||||
b.covered = (state == 1) |
||||
elif state == 2: |
||||
if True not in map(lambda b: b.newpos is not None, self.boxes) \ |
||||
and random.random() > 0.2: |
||||
b1 = random.randint(0, self.n_boxes - 1) |
||||
b2 = random.randint(0, self.n_boxes - 1) |
||||
while b1 == b2: |
||||
b2 = random.randint(0, self.n_boxes - 1) |
||||
self.boxes[b1].swap(self.boxes[b2]) |
||||
|
||||
if state > 0 and state < 5: |
||||
for b in self.boxes: |
||||
b.update(t, dt) |
||||
|
||||
if state == len(self.statetimes) - 1 and state_t > self.statetimes[-1]: |
||||
self.done = True |
||||
|
||||
def draw(self, frame): |
||||
for b in self.boxes: |
||||
if b.newpos is None: |
||||
b.draw(frame) |
||||
for b in self.boxes: |
||||
if b.newpos is not None: |
||||
b.draw(frame) |
||||
|
||||
|
||||
BOXCONTENT = { |
||||
Point(0, 0), |
||||
Point(3, 0), |
||||
Point(0, 2), |
||||
Point(3, 2), |
||||
Point(1, 3), |
||||
Point(2, 3), |
||||
} |
||||
|
||||
|
||||
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 |
||||
gamestart = 0 |
||||
game = None |
||||
while t < args.time or not game.done: |
||||
t += dt |
||||
frame = blup.animation.AnimationFrame(dim, args.delay) |
||||
|
||||
if (game is None or game.done) and t < args.time: |
||||
game = Game(Point(WIDTH, HEIGHT), 6, 2, BOXCONTENT, |
||||
get_random_color(), 0.5) |
||||
gamestart = t |
||||
game.update(t - gamestart, dt) |
||||
game.draw(frame) |
||||
|
||||
anim.addFrame(frame) |
||||
|
||||
|
||||
blup.writebml.writeBml(anim, args.output_file) |
@ -0,0 +1,124 @@
@@ -0,0 +1,124 @@
|
||||
#!/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) |
@ -0,0 +1,133 @@
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
import sys |
||||
import random |
||||
import argparse |
||||
import blup.frame |
||||
import blup.output |
||||
import blup.animation |
||||
import blup.writebml |
||||
import colorsys |
||||
|
||||
|
||||
WIDTH = 22 |
||||
HEIGHT = 16 |
||||
DEPTH = 256 |
||||
|
||||
|
||||
def convert_color(c): |
||||
return list(map(lambda x: int(round(x*(DEPTH-1))), c)) |
||||
|
||||
|
||||
def get_random_color(): |
||||
if random.random() < 0.5: |
||||
s = 1 |
||||
v = random.random() |
||||
else: |
||||
s = random.random() |
||||
v = 1 |
||||
return colorsys.hsv_to_rgb(random.random(), s, v) |
||||
|
||||
|
||||
class Unrath: |
||||
def __init__(self, world): |
||||
self.world = world |
||||
self.shape = set([(0, 0)]) |
||||
shapesize = random.randint(2, 5) |
||||
while len(self.shape) < shapesize: |
||||
p = random.sample(self.shape, 1)[0] |
||||
self.shape.add((p[0]+random.randint(-1, 1), |
||||
p[1]+random.randint(-1, 1))) |
||||
minx = min(map(lambda p: p[0], self.shape)) |
||||
miny = min(map(lambda p: p[1], self.shape)) |
||||
self.shape = {(p[0]+abs(minx), p[1]+abs(miny)) for p in self.shape} |
||||
self.shapewidth = max(map(lambda p: p[0], self.shape)) |
||||
shapeheight = max(map(lambda p: p[1], self.shape)) |
||||
|
||||
y = random.randint(0, HEIGHT-shapeheight) |
||||
if random.random() > 0.5: |
||||
d = 1 |
||||
x = -self.shapewidth |
||||
else: |
||||
d = -1 |
||||
x = WIDTH + self.shapewidth |
||||
self.pos = (x, y) |
||||
self.finished = False |
||||
self.speed = d * random.randint(2, WIDTH/2) |
||||
self.color = get_random_color() |
||||
|
||||
def update(self, dt, nocheck=False): |
||||
if (self.pos[0] + self.shapewidth < 0 and self.speed < 0) or \ |
||||
(self.pos[0] > WIDTH and self.speed > 0): |
||||
self.finished = True |
||||
return |
||||
newpos = (self.pos[0] + dt*self.speed, self.pos[1]) |
||||
newpoints = self.get_points(newpos) |
||||
collision = False |
||||
for unrath in self.world.unraethe - {self}: |
||||
if len(unrath.get_points().intersection(newpoints)) > 0: |
||||
collision = True |
||||
if abs(unrath.speed) > abs(self.speed): |
||||
fast = unrath |
||||
slow = self |
||||
else: |
||||
slow = unrath |
||||
fast = self |
||||
slow.speed = fast.speed * (1.1 + random.random()/10) |
||||
slow.update(dt, True) |
||||
if not collision: |
||||
self.pos = newpos |
||||
|
||||
def get_points(self, pos=None): |
||||
if pos is None: |
||||
pos = self.pos |
||||
return {(int(pos[0] + s[0]), int(pos[1] + s[1])) for s in self.shape} |
||||
|
||||
def draw(self, frame): |
||||
for p in self.get_points(): |
||||
try: |
||||
frame.setPixel(p[0], p[1], convert_color(self.color)) |
||||
except ValueError: |
||||
pass |
||||
|
||||
|
||||
class World: |
||||
def __init__(self, num_unraethe): |
||||
self.num_unraethe = num_unraethe |
||||
self.unraethe = {} |
||||
|
||||
def update(self, dt): |
||||
self.unraethe = set(filter(lambda u: not u.finished, self.unraethe)) |
||||
if len(self.unraethe) < self.num_unraethe: |
||||
self.unraethe.add(Unrath(self)) |
||||
|
||||
for u in self.unraethe: |
||||
u.update(dt) |
||||
|
||||
def draw(self, frame): |
||||
for u in self.unraethe: |
||||
u.draw(frame) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
parser = argparse.ArgumentParser(description='Generate Unrath animations') |
||||
parser.add_argument('-d', '--delay', type=int, default=50) |
||||
parser.add_argument('-t', '--time', type=int, default=15) |
||||
parser.add_argument('-n', '--num-unraethe', type=int, default=5) |
||||
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 |
||||
w = World(args.num_unraethe) |
||||
while t < args.time: |
||||
t += args.delay / 1000 |
||||
frame = blup.animation.AnimationFrame(dim, args.delay) |
||||
w.update(args.delay / 1000) |
||||
w.draw(frame) |
||||
anim.addFrame(frame) |
||||
|
||||
blup.writebml.writeBml(anim, args.output_file) |
Loading…
Reference in new issue