From 16f41a5298b70faaca92b190f67ffacbb1f2736c Mon Sep 17 00:00:00 2001 From: jaseg Date: Fri, 27 May 2016 00:48:52 +0200 Subject: frob --- Makefile | 11 +++++++++ clippy.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++++------------- pixelflut.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 Makefile create mode 100644 pixelflut.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1eba2a7 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ + +all: pixelflut.so + + +pixelflut.so: pixelflut.c + gcc -o $@ -shared -fPIC -Wall -Wpedantic -Wstrict-aliasing $< + + +.PHONY: clean +clean: + rm -f pixelflut.so diff --git a/clippy.py b/clippy.py index 4e67f60..37981f9 100755 --- a/clippy.py +++ b/clippy.py @@ -5,12 +5,13 @@ import random import socket import struct import time -import numpy +import numpy as np import bz2 import os import functools import contextlib import math +import ctypes from PIL import Image @@ -19,7 +20,7 @@ from pixelterm import pixelterm HOST, PORT = "172.23.42.29",2342 CMD_LED_DRAW = 18 -def resize_image(img, size): +def resize_image(img, size, blackbg=True): tw, th = size w, h = img.size a, b = w/tw, h/th @@ -27,8 +28,11 @@ def resize_image(img, size): pos = int((tw-w*f)/2), int((th-h*f)/2) buf = Image.new('RGBA', (tw, th)) buf.paste(img.resize((int(w*f), int(h*f))).convert('RGBA'), pos) - buf2 = Image.new('RGBA', (tw, th), (0, 0, 0, 255)) - return Image.alpha_composite(buf2, buf) + if blackbg: + buf2 = Image.new('RGBA', (tw, th), (0, 0, 0, 255)) + return Image.alpha_composite(buf2, buf) + else: + return buf class Display: def __init__(self): @@ -53,7 +57,29 @@ class Display: @staticmethod def encode_image(img, displaysize): - return numpy.frombuffer(Display.do_gamma(resize_image(img, displaysize), 0.5).convert('1').tobytes(), dtype='1b') + return np.frombuffer(Display.do_gamma(resize_image(img, displaysize), 0.5).convert('1').tobytes(), dtype='1b') + +class Pixelflut: + def __init__(self, host, port, x, y, w, h): + self.host, self.port = host.encode(), port + self.x, self.y = x, y + self.w, self.h = w, h + self.dbuf = np.zeros(w*h*4, dtype=np.uint8) + self.so = ctypes.CDLL('./pixelflut.so') + self.sock = None + + def sendframe(self, frame): + np.copyto(self.dbuf, frame) + cptr = self.dbuf.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8)) + if self.sock is None: + while self.sock is None or self.sock < 0: + time.sleep(1) + self.sock = self.so.cct(self.host, self.port) + if self.so.sendframe(self.sock, cptr, self.w, self.h, self.x, self.y): + self.so.discct(self.sock) + + def encode_image(self, img): + return np.array(resize_image(img, (self.w, self.h), blackbg=False)).reshape(self.w*self.h*4) def weightedChoice(choices, default=None): acc = 0 @@ -81,14 +107,15 @@ class Agent: self.picmap = Image.open(path / 'map.png') self.path = path - def __call__(self, action): + def __call__(self, action, sleep=True): for frame in self._animate(action): # print('frame:', frame) if 'images_encoded' in frame: # some frames contain branch info and sound, but no images yield frame['images_encoded'] - time.sleep(frame['duration']/1000) + if sleep: + time.sleep(frame['duration']/1000) - def precalculate_images(self, dsp, termsize): + def precalculate_images(self, pf, dsp, termsize): print('\033[93mPrecalculating images\033[0m') total = sum(1 for ani in self.config['animations'].values() for f in ani['frames'] if 'images' in f) i = 0 @@ -97,15 +124,16 @@ class Agent: if 'images' in f: print(('(\033[38;5;245m{: '+str(1+int(math.log10(total)))+'}/{}\033[0m) ').format(i, total), end='') i += 1 - f['images_encoded'] = self._precalculate_one_image(tuple(f['images'][0]), dsp, termsize) + f['images_encoded'] = self._precalculate_one_image(tuple(f['images'][0]), pf, dsp, termsize) print() print('\033[93mdone.\033[0m') self._precalculate_one_image.cache_clear() @functools.lru_cache(maxsize=None) - def _precalculate_one_image(self, coords, dsp, termsize): + def _precalculate_one_image(self, coords, pf, dsp, termsize): img = self._get_image(*coords) - return ( dsp.encode_image(img, dsp.size) if dsp else None, + return ( pf.encode_image(img) if pf else None, + dsp.encode_image(img, dsp.size) if dsp else None, pixelterm.termify_pixels(resize_image(img, termsize)) if termsize else None ) def _animate(self, action): @@ -132,9 +160,11 @@ if __name__ == '__main__': parser.add_argument('-a', '--agent', default='Clippy') parser.add_argument('-e', '--endless', action='store_true') parser.add_argument('-d', '--display', action='store_true') + parser.add_argument('-p', '--pixelflut', type=str, default='94.45.232.225:1234') parser.add_argument('-t', '--terminal', action='store_true') parser.add_argument('-x', '--termsize', type=str) parser.add_argument('-s', '--socket', action='store_true') + parser.add_argument('-n', '--nosleep', action='store_true') parser.add_argument('-b', '--bind', type=str, default='0.0.0.0:2342') parser.add_argument('action', default='Greeting', nargs='?') args = parser.parse_args() @@ -149,6 +179,17 @@ if __name__ == '__main__': sys.exit(0) dsp = Display() if args.display else None + + if args.pixelflut: + target, *params = args.pixelflut.split('@') + host, port = target.split(':') + port = int(port) + x, y, *_r = params[0].split(',') if params else (0, 0, None) + w, h = _r if _r else (320, 240) + x, y, w, h = map(int, (x, y, w, h)) + pf = Pixelflut(host, port, x, y, w, h) if args.pixelflut else None + else: + pf = None agent = Agent(agent_path) if args.socket: tx, ty = (args.termsize or '60x30').split('x') @@ -157,7 +198,7 @@ if __name__ == '__main__': tx, ty = args.termsize.split('x') or os.get_terminal_size() tx, ty = int(tx), int(ty) termsize = (tx, ty*2) if args.terminal or args.socket else None - agent.precalculate_images(dsp, termsize) + agent.precalculate_images(pf, dsp, termsize) if args.socket: import socketserver @@ -169,7 +210,7 @@ if __name__ == '__main__': while True: action = random.choice(agent.animations) print('[\033[38;5;245m{}\033[0m] Playing: {}'.format(self.client_address[0], action)) - for _img_dsp, img_term in agent(action): + for _img_pf, _img_dsp, img_term in agent(action): self.request.sendall(b'\033[H'+img_term.encode()) host, port = args.bind.split(':') port = int(port) @@ -180,16 +221,22 @@ if __name__ == '__main__': if random.random() > 0.2: action = random.choice(agent.animations) print('Playing:', action) - for img_dsp, img_term in agent(action): + for img_pf, img_dsp, img_term in agent(action, not args.nosleep): if args.terminal: print('\033[H'+img_term) if args.display: dsp.sendframe(img_dsp) - time.sleep(1) + if args.pixelflut: + pf.sendframe(img_pf) + if not args.nosleep: + time.sleep(1) else: - for img_dsp, img_term in agent(args.action): + for img_pf, img_dsp, img_term in agent(args.action, not args.nosleep): if args.terminal: print(pixelterm.termify_pixels( resize_image(img, termsize))) if args.display: dsp.sendframe(img_dsp) + if args.pixelflut: + pf.sendframe(img_pf) + diff --git a/pixelflut.c b/pixelflut.c new file mode 100644 index 0000000..15dcc55 --- /dev/null +++ b/pixelflut.c @@ -0,0 +1,72 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PIXEL_FORMAT "PX %zd %zd %02x%02x%02x\n" +int cct(const char *target, int port) { + printf("Reconnecting %s:%d\n", target, port); + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (!sockfd) { + fprintf(stderr, "No sockfd.\n"); + return -1; + } + + struct sockaddr_in serv_addr; + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(port); + if (inet_pton(AF_INET, target, &serv_addr.sin_addr) != 1) { + fprintf(stderr, "Address error. \"%s\"\n", target); + return -2; + } + + if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) { + fprintf(stderr, "Connect error.\n"); + return -3; + } + + return sockfd; +} + +int sendframe(int fd, uint8_t *img, int w, int h, int ox, int oy) { + static unsigned long fcnt=0; + printf("frame %lu %dx%d @pos %dx%d\n", fcnt++, w, h, ox, oy); + int fmtlen = snprintf(NULL, 0, PIXEL_FORMAT, (size_t)1000, (size_t)1000, 0xff, 0xff, 0xff); + char *out = malloc(1400); + if (!out) { + fprintf(stderr, "Malloc error.\n"); + return -4; + } + char *p = out; + for (size_t x=0; x 1400-fmtlen-1) { + if (send(fd, out, p-out, 0) < 0) { + fprintf(stderr, "Send error. %d %s\n", errno, strerror(errno)); + return -5; + } + p = out; + } + } + } + free(out); + usleep(1000); + return 0; +} + +void discct(int fd) { + close(fd); +} -- cgit