Fr3deric
7 years ago
1 changed files with 150 additions and 0 deletions
@ -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) |
Loading…
Reference in new issue