From 916aced1bef07001ef4eee2a1cde6cd6e33b4bc3 Mon Sep 17 00:00:00 2001 From: jaseg Date: Fri, 3 Jan 2014 00:10:20 +0100 Subject: Now with even more abstract art. --- host/matelight/Makefile | 4 +- host/matelight/color.c | 291 +++++++++++++++++++++++++++++++++++++++++ host/matelight/color.h | 21 +++ host/matelight/font.c | 5 +- host/matelight/font.h | 5 +- host/matelight/font.py | 5 - host/matelight/genpal.py | 35 +++++ host/matelight/host.py | 19 --- host/matelight/listeners.py | 98 -------------- host/matelight/main.c | 256 ++++++++++++++++++++++++++++++++++-- host/matelight/nyancat-test.py | 29 ---- host/matelight/queuemgr.py | 52 -------- host/matelight/renderers.py | 154 ---------------------- host/matelight/scroll-test.py | 14 -- 14 files changed, 600 insertions(+), 388 deletions(-) create mode 100644 host/matelight/color.c create mode 100644 host/matelight/color.h delete mode 100644 host/matelight/font.py create mode 100755 host/matelight/genpal.py delete mode 100644 host/matelight/host.py delete mode 100755 host/matelight/listeners.py delete mode 100755 host/matelight/nyancat-test.py delete mode 100644 host/matelight/queuemgr.py delete mode 100644 host/matelight/renderers.py delete mode 100755 host/matelight/scroll-test.py diff --git a/host/matelight/Makefile b/host/matelight/Makefile index 2a7e971..1f90145 100644 --- a/host/matelight/Makefile +++ b/host/matelight/Makefile @@ -1,6 +1,6 @@ -all: main.c font.c font.h - gcc -std=gnu11 -Wall -lm -o matelight -g -O0 main.c font.c +all: main.c font.c font.h color.c color.h + gcc -std=gnu11 -Wall -lm -o matelight -g -O0 main.c font.c color.c clean: rm matelight diff --git a/host/matelight/color.c b/host/matelight/color.c new file mode 100644 index 0000000..938bdf1 --- /dev/null +++ b/host/matelight/color.c @@ -0,0 +1,291 @@ + +#include "color.h" +#include +#include + +int xterm_color_index(color_t c){ + int candidate = 0; + int best_distance = 0x7fffffff; + for(int i=0; i<256; i++){ + color_t k = colortable[i]; + int tmp = abs(c.r - k.r); + tmp *= tmp; + int distance = tmp; + if(distance > best_distance) + continue; + tmp = abs(c.g - k.g); + tmp *= tmp; + distance += tmp; + if(distance > best_distance) + continue; + tmp = abs(c.b - k.b); + tmp *= tmp; + distance += tmp; + if(distance > best_distance) + continue; + best_distance = distance; + candidate = i; + } + return candidate; +} + +color_t colortable[256] = { + {0x00, 0x00, 0x00}, + {0xa8, 0x00, 0x00}, + {0x00, 0xa8, 0x00}, + {0xa8, 0x54, 0x00}, + {0x00, 0x00, 0xa8}, + {0xa8, 0x00, 0xa8}, + {0x00, 0xa8, 0xa8}, + {0xa8, 0xa8, 0xa8}, + {0x54, 0x54, 0x54}, + {0xfc, 0x54, 0x54}, + {0x54, 0xfc, 0x54}, + {0xfc, 0xfc, 0x54}, + {0x54, 0x54, 0xfc}, + {0xfc, 0x54, 0xfc}, + {0x54, 0xfc, 0xfc}, + {0xfc, 0xfc, 0xfc}, + {0x00, 0x00, 0x00}, + {0x00, 0x00, 0x5f}, + {0x00, 0x00, 0x87}, + {0x00, 0x00, 0xaf}, + {0x00, 0x00, 0xd7}, + {0x00, 0x00, 0xff}, + {0x00, 0x5f, 0x00}, + {0x00, 0x5f, 0x5f}, + {0x00, 0x5f, 0x87}, + {0x00, 0x5f, 0xaf}, + {0x00, 0x5f, 0xd7}, + {0x00, 0x5f, 0xff}, + {0x00, 0x87, 0x00}, + {0x00, 0x87, 0x5f}, + {0x00, 0x87, 0x87}, + {0x00, 0x87, 0xaf}, + {0x00, 0x87, 0xd7}, + {0x00, 0x87, 0xff}, + {0x00, 0xaf, 0x00}, + {0x00, 0xaf, 0x5f}, + {0x00, 0xaf, 0x87}, + {0x00, 0xaf, 0xaf}, + {0x00, 0xaf, 0xd7}, + {0x00, 0xaf, 0xff}, + {0x00, 0xd7, 0x00}, + {0x00, 0xd7, 0x5f}, + {0x00, 0xd7, 0x87}, + {0x00, 0xd7, 0xaf}, + {0x00, 0xd7, 0xd7}, + {0x00, 0xd7, 0xff}, + {0x00, 0xff, 0x00}, + {0x00, 0xff, 0x5f}, + {0x00, 0xff, 0x87}, + {0x00, 0xff, 0xaf}, + {0x00, 0xff, 0xd7}, + {0x00, 0xff, 0xff}, + {0x5f, 0x00, 0x00}, + {0x5f, 0x00, 0x5f}, + {0x5f, 0x00, 0x87}, + {0x5f, 0x00, 0xaf}, + {0x5f, 0x00, 0xd7}, + {0x5f, 0x00, 0xff}, + {0x5f, 0x5f, 0x00}, + {0x5f, 0x5f, 0x5f}, + {0x5f, 0x5f, 0x87}, + {0x5f, 0x5f, 0xaf}, + {0x5f, 0x5f, 0xd7}, + {0x5f, 0x5f, 0xff}, + {0x5f, 0x87, 0x00}, + {0x5f, 0x87, 0x5f}, + {0x5f, 0x87, 0x87}, + {0x5f, 0x87, 0xaf}, + {0x5f, 0x87, 0xd7}, + {0x5f, 0x87, 0xff}, + {0x5f, 0xaf, 0x00}, + {0x5f, 0xaf, 0x5f}, + {0x5f, 0xaf, 0x87}, + {0x5f, 0xaf, 0xaf}, + {0x5f, 0xaf, 0xd7}, + {0x5f, 0xaf, 0xff}, + {0x5f, 0xd7, 0x00}, + {0x5f, 0xd7, 0x5f}, + {0x5f, 0xd7, 0x87}, + {0x5f, 0xd7, 0xaf}, + {0x5f, 0xd7, 0xd7}, + {0x5f, 0xd7, 0xff}, + {0x5f, 0xff, 0x00}, + {0x5f, 0xff, 0x5f}, + {0x5f, 0xff, 0x87}, + {0x5f, 0xff, 0xaf}, + {0x5f, 0xff, 0xd7}, + {0x5f, 0xff, 0xff}, + {0x87, 0x00, 0x00}, + {0x87, 0x00, 0x5f}, + {0x87, 0x00, 0x87}, + {0x87, 0x00, 0xaf}, + {0x87, 0x00, 0xd7}, + {0x87, 0x00, 0xff}, + {0x87, 0x5f, 0x00}, + {0x87, 0x5f, 0x5f}, + {0x87, 0x5f, 0x87}, + {0x87, 0x5f, 0xaf}, + {0x87, 0x5f, 0xd7}, + {0x87, 0x5f, 0xff}, + {0x87, 0x87, 0x00}, + {0x87, 0x87, 0x5f}, + {0x87, 0x87, 0x87}, + {0x87, 0x87, 0xaf}, + {0x87, 0x87, 0xd7}, + {0x87, 0x87, 0xff}, + {0x87, 0xaf, 0x00}, + {0x87, 0xaf, 0x5f}, + {0x87, 0xaf, 0x87}, + {0x87, 0xaf, 0xaf}, + {0x87, 0xaf, 0xd7}, + {0x87, 0xaf, 0xff}, + {0x87, 0xd7, 0x00}, + {0x87, 0xd7, 0x5f}, + {0x87, 0xd7, 0x87}, + {0x87, 0xd7, 0xaf}, + {0x87, 0xd7, 0xd7}, + {0x87, 0xd7, 0xff}, + {0x87, 0xff, 0x00}, + {0x87, 0xff, 0x5f}, + {0x87, 0xff, 0x87}, + {0x87, 0xff, 0xaf}, + {0x87, 0xff, 0xd7}, + {0x87, 0xff, 0xff}, + {0xaf, 0x00, 0x00}, + {0xaf, 0x00, 0x5f}, + {0xaf, 0x00, 0x87}, + {0xaf, 0x00, 0xaf}, + {0xaf, 0x00, 0xd7}, + {0xaf, 0x00, 0xff}, + {0xaf, 0x5f, 0x00}, + {0xaf, 0x5f, 0x5f}, + {0xaf, 0x5f, 0x87}, + {0xaf, 0x5f, 0xaf}, + {0xaf, 0x5f, 0xd7}, + {0xaf, 0x5f, 0xff}, + {0xaf, 0x87, 0x00}, + {0xaf, 0x87, 0x5f}, + {0xaf, 0x87, 0x87}, + {0xaf, 0x87, 0xaf}, + {0xaf, 0x87, 0xd7}, + {0xaf, 0x87, 0xff}, + {0xaf, 0xaf, 0x00}, + {0xaf, 0xaf, 0x5f}, + {0xaf, 0xaf, 0x87}, + {0xaf, 0xaf, 0xaf}, + {0xaf, 0xaf, 0xd7}, + {0xaf, 0xaf, 0xff}, + {0xaf, 0xd7, 0x00}, + {0xaf, 0xd7, 0x5f}, + {0xaf, 0xd7, 0x87}, + {0xaf, 0xd7, 0xaf}, + {0xaf, 0xd7, 0xd7}, + {0xaf, 0xd7, 0xff}, + {0xaf, 0xff, 0x00}, + {0xaf, 0xff, 0x5f}, + {0xaf, 0xff, 0x87}, + {0xaf, 0xff, 0xaf}, + {0xaf, 0xff, 0xd7}, + {0xaf, 0xff, 0xff}, + {0xd7, 0x00, 0x00}, + {0xd7, 0x00, 0x5f}, + {0xd7, 0x00, 0x87}, + {0xd7, 0x00, 0xaf}, + {0xd7, 0x00, 0xd7}, + {0xd7, 0x00, 0xff}, + {0xd7, 0x5f, 0x00}, + {0xd7, 0x5f, 0x5f}, + {0xd7, 0x5f, 0x87}, + {0xd7, 0x5f, 0xaf}, + {0xd7, 0x5f, 0xd7}, + {0xd7, 0x5f, 0xff}, + {0xd7, 0x87, 0x00}, + {0xd7, 0x87, 0x5f}, + {0xd7, 0x87, 0x87}, + {0xd7, 0x87, 0xaf}, + {0xd7, 0x87, 0xd7}, + {0xd7, 0x87, 0xff}, + {0xd7, 0xaf, 0x00}, + {0xd7, 0xaf, 0x5f}, + {0xd7, 0xaf, 0x87}, + {0xd7, 0xaf, 0xaf}, + {0xd7, 0xaf, 0xd7}, + {0xd7, 0xaf, 0xff}, + {0xd7, 0xd7, 0x00}, + {0xd7, 0xd7, 0x5f}, + {0xd7, 0xd7, 0x87}, + {0xd7, 0xd7, 0xaf}, + {0xd7, 0xd7, 0xd7}, + {0xd7, 0xd7, 0xff}, + {0xd7, 0xff, 0x00}, + {0xd7, 0xff, 0x5f}, + {0xd7, 0xff, 0x87}, + {0xd7, 0xff, 0xaf}, + {0xd7, 0xff, 0xd7}, + {0xd7, 0xff, 0xff}, + {0xff, 0x00, 0x00}, + {0xff, 0x00, 0x5f}, + {0xff, 0x00, 0x87}, + {0xff, 0x00, 0xaf}, + {0xff, 0x00, 0xd7}, + {0xff, 0x00, 0xff}, + {0xff, 0x5f, 0x00}, + {0xff, 0x5f, 0x5f}, + {0xff, 0x5f, 0x87}, + {0xff, 0x5f, 0xaf}, + {0xff, 0x5f, 0xd7}, + {0xff, 0x5f, 0xff}, + {0xff, 0x87, 0x00}, + {0xff, 0x87, 0x5f}, + {0xff, 0x87, 0x87}, + {0xff, 0x87, 0xaf}, + {0xff, 0x87, 0xd7}, + {0xff, 0x87, 0xff}, + {0xff, 0xaf, 0x00}, + {0xff, 0xaf, 0x5f}, + {0xff, 0xaf, 0x87}, + {0xff, 0xaf, 0xaf}, + {0xff, 0xaf, 0xd7}, + {0xff, 0xaf, 0xff}, + {0xff, 0xd7, 0x00}, + {0xff, 0xd7, 0x5f}, + {0xff, 0xd7, 0x87}, + {0xff, 0xd7, 0xaf}, + {0xff, 0xd7, 0xd7}, + {0xff, 0xd7, 0xff}, + {0xff, 0xff, 0x00}, + {0xff, 0xff, 0x5f}, + {0xff, 0xff, 0x87}, + {0xff, 0xff, 0xaf}, + {0xff, 0xff, 0xd7}, + {0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00}, + {0x12, 0x12, 0x12}, + {0x1c, 0x1c, 0x1c}, + {0x26, 0x26, 0x26}, + {0x30, 0x30, 0x30}, + {0x3a, 0x3a, 0x3a}, + {0x44, 0x44, 0x44}, + {0x4e, 0x4e, 0x4e}, + {0x58, 0x58, 0x58}, + {0x62, 0x62, 0x62}, + {0x6c, 0x6c, 0x6c}, + {0x76, 0x76, 0x76}, + {0x80, 0x80, 0x80}, + {0x8a, 0x8a, 0x8a}, + {0x94, 0x94, 0x94}, + {0x9e, 0x9e, 0x9e}, + {0xa8, 0xa8, 0xa8}, + {0xb2, 0xb2, 0xb2}, + {0xbc, 0xbc, 0xbc}, + {0xc6, 0xc6, 0xc6}, + {0xd0, 0xd0, 0xd0}, + {0xda, 0xda, 0xda}, + {0xe4, 0xe4, 0xe4}, + {0xee, 0xee, 0xee} +}; + + diff --git a/host/matelight/color.h b/host/matelight/color.h new file mode 100644 index 0000000..48f325b --- /dev/null +++ b/host/matelight/color.h @@ -0,0 +1,21 @@ +#ifndef __COLOR_H__ +#define __COLOR_H__ + +#include + +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} color_t; + +int xterm_color_index(color_t c); + +// gray +#define DEFAULT_FG_COLOR 7 +// black +#define DEFAULT_BG_COLOR 0 + +extern color_t colortable[256]; + +#endif//__COLOR_H__ diff --git a/host/matelight/font.c b/host/matelight/font.c index 53d27b9..f22f05b 100644 --- a/host/matelight/font.c +++ b/host/matelight/font.c @@ -5,7 +5,7 @@ #include #include -void render_glyph(glyph_t *g, uint8_t *buf, unsigned int bufwidth, unsigned int offx, unsigned int offy){ +void render_glyph(glyph_t *g, uint8_t *buf, unsigned int bufwidth, unsigned int offx, unsigned int offy, color_t fg, color_t bg){ unsigned int bitmap_row_width = g->width/8; uint8_t *bitmap = ((uint8_t *)g) + sizeof(glyph_t); for(unsigned int y=0; y < g->height; y++){ @@ -16,7 +16,8 @@ void render_glyph(glyph_t *g, uint8_t *buf, unsigned int bufwidth, unsigned int } uint8_t *p = buf + (offy+y)*bufwidth + offx; for(unsigned int x=0; x < g->width; x++){ - *p++ = (data&(1<<(g->width-1))) ? 1 : 0; + color_t c = (data&(1<<(g->width-1))) ? fg : bg; + *((color_t *)(p++)) = c; data <<= 1; } } diff --git a/host/matelight/font.h b/host/matelight/font.h index e3e2e60..d21100c 100644 --- a/host/matelight/font.h +++ b/host/matelight/font.h @@ -4,6 +4,7 @@ #include #include +#include "color.h" // CAUTION: A glyph struct is always followed by the glyph's bitmap. typedef struct { @@ -16,10 +17,12 @@ typedef struct { // Size of Unicode's basic multilingual plane #define BLP_SIZE 65536 +#define MAX_CSI_ELEMENTS 8 + // We could also use some fancy hashtable here, but unifont includes about 57k glyphs so we would hardly save any memory. int read_bdf(FILE *f, glyph_t **glyph_table, unsigned int glyph_table_size); // Requires buf to point to a buffer at least of size glyph->width*glyph->height. -void render_glyph(glyph_t *glyph, uint8_t *buf, unsigned int bufwidth, unsigned int offx, unsigned int offy); +void render_glyph(glyph_t *glyph, uint8_t *buf, unsigned int bufwidth, unsigned int offx, unsigned int offy, color_t fg, color_t bg); #endif//__FONT_H__ diff --git a/host/matelight/font.py b/host/matelight/font.py deleted file mode 100644 index a1c1dd6..0000000 --- a/host/matelight/font.py +++ /dev/null @@ -1,5 +0,0 @@ -from bdflib import reader as bdfreader # Used to read the bitmap font - -FONT = bdfreader.read_bdf(iter(open('fonts/unifont-6.3.20131020.bdf').readlines())) -FONT_HEIGHT = 16 - diff --git a/host/matelight/genpal.py b/host/matelight/genpal.py new file mode 100755 index 0000000..01fe611 --- /dev/null +++ b/host/matelight/genpal.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +xterm_colors = [ + (0x00, 0x00, 0x00), + (0xa8, 0x00, 0x00), + (0x00, 0xa8, 0x00), + (0xa8, 0x54, 0x00), + (0x00, 0x00, 0xa8), + (0xa8, 0x00, 0xa8), + (0x00, 0xa8, 0xa8), + (0xa8, 0xa8, 0xa8), + (0x54, 0x54, 0x54), + (0xfc, 0x54, 0x54), + (0x54, 0xfc, 0x54), + (0xfc, 0xfc, 0x54), + (0x54, 0x54, 0xfc), + (0xfc, 0x54, 0xfc), + (0x54, 0xfc, 0xfc), + (0xfc, 0xfc, 0xfc)] + +# colors 16..232: the 6x6x6 color cube +_valuerange = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff) +for i in range(217): + r = _valuerange[(i // 36) % 6] + g = _valuerange[(i // 6) % 6] + b = _valuerange[i % 6] + xterm_colors.append((r, g, b)) + +# colors 233..253: grayscale +for i in range(1, 24): + v = 8 + i * 10 + xterm_colors.append((v, v, v)) + +for r,g,b in xterm_colors: + print("\t{{{:#04x}, {:#04x}, {:#04x}}},".format(r,g,b)) diff --git a/host/matelight/host.py b/host/matelight/host.py deleted file mode 100644 index 4fa8578..0000000 --- a/host/matelight/host.py +++ /dev/null @@ -1,19 +0,0 @@ -import usb -import colorsys -import numpy as np -from config import * -import itertools - -dev = usb.core.find(idVendor=0x1cbe, idProduct=0x0003) - -def sendframe(framedata): - # not isinstance(framedata, np.array) or - if framedata.shape != (DISPLAY_HEIGHT, DISPLAY_WIDTH, 3) or framedata.dtype != np.uint8: - raise ValueError('framedata must be a ({}, {}, 3)-numpy array of uint8s. Got a {}-numpy array of {}'.format(DISPLAY_HEIGHT, DISPLAY_WIDTH, framedata.shape, framedata.dtype)) - - for cy, cx in itertools.product(range(CRATES_Y), range(CRATES_X)): - cratedata = framedata[cy*CRATE_HEIGHT:(cy+1)*CRATE_HEIGHT, cx*CRATE_WIDTH:(cx+1)*CRATE_WIDTH] - # Send framebuffer data - dev.write(0x01, bytes([0, cx, cy])+bytes(list(cratedata.flatten()))) - # Send latch command - dev.write(0x01, b'\x01') diff --git a/host/matelight/listeners.py b/host/matelight/listeners.py deleted file mode 100755 index f390389..0000000 --- a/host/matelight/listeners.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python3 -from socketserver import * -import socket -import threading -import zlib -import random -import struct -import host -import numpy as np -import time -import sys -import traceback -import renderers -from PIL import Image, ImageSequence -from config import * -# Loading frame (for the big font file) -img = Image.open(open('../nyancat.png', 'rb')) -frame = np.array(img.convert('RGB').getdata(), dtype=np.uint8).reshape((DISPLAY_HEIGHT, DISPLAY_WIDTH, 3)) -host.sendframe(frame) -from font import * - -UDP_THRES = 1.0 - -class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass -class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass - -default_renderers = [renderers.TextRenderer('\x1B[92mMate Light\x1B[93m@\x1B[92mPlay store or \x1B[94;101mtcp://ml.jaseg.net:1337\x1B[0;91m ♥ '), - renderers.TextRenderer('\x1B[92mMate Light\x1B[0;91m ♥ \x1B[92mUnicode'), - renderers.TextRenderer('\x1B[92mMate Light\x1B[0m powered by \x1B[95mMicrosoft™ \x1B[96mMarquee Manager® Pro')] -global renderer, count -renderer = default_renderers[0] -count = 0 -lastudp = 0 - -class MateLightUDPHandler(BaseRequestHandler): - def handle(self): - try: - global lastudp - data = self.request[0].strip() - if len(data) != FRAME_SIZE+4: - #raise ValueError('Invalid frame size: Expected {}, got {}'.format(FRAME_SIZE+4, len(data))) - return - frame = data[:-4] - crc1, = struct.unpack('!I', data[-4:]) - crc2, = zlib.crc32(frame, 0), - #if crc1 != crc2: - # raise ValueError('Invalid frame CRC checksum: Expected {}, got {}'.format(crc2, crc1)) - #socket.sendto(b'ACK', self.client_address) - a = np.array(list(frame), dtype=np.uint8) - lastudp = time.time() - host.sendframe(a.reshape((DISPLAY_HEIGHT, DISPLAY_WIDTH, 3))) - except Exception as e: - print('Error receiving UDP frame:', e) - ex_type, ex, tb = sys.exc_info() - traceback.print_tb(tb) - -class MateLightTCPTextHandler(BaseRequestHandler): - def handle(self): - try: - data = str(self.request.recv(1024).strip(), 'UTF-8') - if len(data) > 140: - self.request.sendall('TOO MUCH INFORMATION!\n') - return - global renderer, count - print(data+'\x1B[0m') - renderer = renderers.TextRenderer(data) - count = 3 - self.request.sendall(b'KTHXBYE!\n') - except: - pass - -TCPServer.allow_reuse_address = True -server = TCPServer(('', 1337), MateLightTCPTextHandler) -t = threading.Thread(target=server.serve_forever) -t.daemon = True -t.start() - -UDPServer.allow_reuse_address = True -userver = UDPServer(('', 1337), MateLightUDPHandler) -t = threading.Thread(target=userver.serve_forever) -t.daemon = True -t.start() - -while True: - global renderer, count, lastudp - foo = renderer - if count == 0: - renderer = random.choice(default_renderers) - else: - count = count - 1 - for frame, delay in foo.frames(): - #print(list(frame.flatten())) - now = time.time() - if now-lastudp > UDP_THRES: - host.sendframe(np.swapaxes(frame, 0, 1)) - else: - time.sleep(0.1) - diff --git a/host/matelight/main.c b/host/matelight/main.c index 7a23a0a..48c50d9 100644 --- a/host/matelight/main.c +++ b/host/matelight/main.c @@ -1,5 +1,6 @@ #include "font.h" +#include "color.h" #include #include #include @@ -7,6 +8,7 @@ #include #include #include +#include /* CAUTION: REQUIRES INPUT TO BE \0-TERMINATED */ int console_render(char *s, glyph_t **glyph_table, unsigned int glyph_table_size){ @@ -53,7 +55,8 @@ int console_render(char *s, glyph_t **glyph_table, unsigned int glyph_table_size // For easier rendering on the terminal, round up to multiples of two gbufheight += gbufheight&1; - unsigned int gbufsize = gbufwidth*gbufheight; + // gbuf uses 3 bytes per color for r, g and b + unsigned int gbufsize = gbufwidth*3*gbufheight; gbuf = malloc(gbufsize); if(gbuf == 0){ fprintf(stderr, "Cannot malloc() %d bytes.\n", gbufsize); @@ -64,31 +67,260 @@ int console_render(char *s, glyph_t **glyph_table, unsigned int glyph_table_size unsigned int x = 0; p = s; memset(&ps, 0, sizeof(mbstate_t)); + struct { + color_t fg; + color_t bg; + int blink:4; + int bold:1; // TODO + int underline:1; + int strikethrough:1; + int fraktur:1; // TODO See: Flat10 Fraktur font + int invert:1; + } style = { + colortable[DEFAULT_FG_COLOR], colortable[DEFAULT_BG_COLOR], 0, 0, 0, 0, 0, 0 + }; for(;;){ + // NOTE: This nested escape sequence parsing does not contain any unicode-awareness whatsoever + if(*p == '\033'){ // Escape sequence YAY + char *sequence_start = p++; + if(*p == '['){ // This was a CSI! + long elems[MAX_CSI_ELEMENTS]; + int nelems; + for(nelems = 0; nelemsy usually is a negative index of the glyph's baseline measured from the glyph's bottom + int uly = gbufheight + g->y; + for(int i=0; iwidth; i++){ + if(style.strikethrough) + *((color_t *)(gbuf + (sty*gbufwidth + i)*3)) = fg; + if(style.underline) + *((color_t *)(gbuf + (uly*gbufwidth + i)*3)) = fg; + } + } x += g->width; } + for(unsigned int y=0; y < gbufheight; y++){ + for(unsigned int x=0; x < gbufwidth; x++){ + color_t c = *((color_t *)(gbuf + (y*gbufwidth + x)*3)); + //printf("\033[0m%02x,%02x,%02x-%02x\033[38;5;%dm█", c.r, c.g, c.b, xterm_color_index(c), xterm_color_index(c)); + printf("\033[38;5;%dm█", xterm_color_index(c)); + } + printf("\n"); + } + return 0; + color_t lastfg = {0, 0, 0}, lastbg = {0, 0, 0}; + printf("\e[38;5;0;48;5;0m"); for(unsigned int y=0; y < gbufheight; y+=2){ for(unsigned int x=0; x < gbufwidth; x++){ //Da magicks: ▀█▄ - char c1 = gbuf[y*gbufwidth + x]; - char c2 = gbuf[(y+1)*gbufwidth + x]; - if(c1 && c2) - printf("█"); - else if(c1 && !c2) - printf("▀"); - else if(!c1 && c2) - printf("▄"); - else - printf(" "); + color_t ct = *((color_t *)(gbuf + (y*gbufwidth + x)*3)); // Top pixel + color_t cb = *((color_t *)(gbuf + ((y+1)*gbufwidth + x)*3)); // Bottom pixel + if(!memcmp(&ct, &lastfg, sizeof(color_t))){ + if(!memcmp(&cb, &lastbg, sizeof(color_t))){ + printf("▀"); + }else if(!memcmp(&cb, &lastfg, sizeof(color_t))){ + printf("█"); + }else{ + printf("\033[48;5;%dm▀", xterm_color_index(cb)); + lastbg = cb; + } + }else if(!memcmp(&ct, &lastbg, sizeof(color_t))){ + if(!memcmp(&cb, &lastfg, sizeof(color_t))){ + printf("▄"); + }else if(!memcmp(&cb, &lastbg, sizeof(color_t))){ + printf(" "); + }else{ + printf("\033[38;5;%dm▄", xterm_color_index(cb)); + lastfg = cb; + } + }else{ // No matches for the upper pixel + if(!memcmp(&cb, &lastfg, sizeof(color_t))){ + printf("\033[48;5;%dm▄", xterm_color_index(ct)); + lastbg = ct; + }else if(!memcmp(&cb, &lastbg, sizeof(color_t))){ + printf("\033[38;5;%dm▀", xterm_color_index(ct)); + lastfg = ct; + }else{ + printf("\033[38;5;%d;48;5;%dm▀", xterm_color_index(ct), xterm_color_index(cb)); + lastfg = ct; + lastbg = cb; + } + } } printf("\n"); } diff --git a/host/matelight/nyancat-test.py b/host/matelight/nyancat-test.py deleted file mode 100755 index 73fd28e..0000000 --- a/host/matelight/nyancat-test.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 -import host -import numpy as np -from config import * -from PIL import Image, ImageSequence -import time - -img1 = Image.open(open('../nyancat.png', 'rb')) -img2 = Image.open(open('../nyancat2.png', 'rb')) -scroller = Image.open(open('../scroller.png', 'rb')) -datas = [] -for img in [img1, img2]: - im = img.convert("RGB") - im.thumbnail((DISPLAY_WIDTH, DISPLAY_HEIGHT), Image.NEAREST) - data = np.array(im.getdata(), dtype=np.uint8) - datas += [data.reshape((DISPLAY_HEIGHT, DISPLAY_WIDTH, 3))] - -im = scroller.convert("RGB") -bar = np.array(im.getdata(), dtype=np.uint8) -foo = bar.reshape((DISPLAY_HEIGHT, 300, 3)) - -while True: - for i in range(60): - for data in datas: - host.sendframe(data) - time.sleep(0.1) - for i in range(260): - host.sendframe(foo[:, i:i+40, :]) - diff --git a/host/matelight/queuemgr.py b/host/matelight/queuemgr.py deleted file mode 100644 index df75309..0000000 --- a/host/matelight/queuemgr.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python3 - -from renderers import TextRenderer, ImageRenderer -import host, config -import time, math - -score = lambda now, last, lifetime, priority, item: priority*math.log(now-last)/(10.0+item.duration) - -class FuzzyQueue: - def __init__(self, default): - self._default = default - self.put(default, 0.0, 0) - self._l = [] - - def put(self, item, priority=1.0, lifetime=0): - lifetime += time.time() - self._l.append((0, lifetime, priority, item)) - - def pop(self): - """ Get an item from the queue - - NOTE: This is *not* a regular pop, as it does not necessarily remove the item from the queue. - """ - now = time.time() - # Choose item based on last used and priority - _, index, (_, lifetime, priority, item) = max(sorted([(score(now, *v), i, v) for i, v in self._l])) - # If item's lifetime is exceeded, remove - if lifetime < now and item is not self._default: - del self._l[index] - # Otherwise, set item's last played time - self._l[index] = (now, lifetime, prioity, item) - # Finally, return - return item - -q = FuzzyQueue() - -def insert_text(text, priority=1.0, lifetime=0, escapes=True): - q.put(TextRenderer(text, escapes), priority, lifetime) - -def insert_image(image, priority=1.0, lifetime=0): - q.put(ImageRenderer(image), priority, lifetime) - -def render_thread(): - while True: - start = time.time() - for frame, delay in q.pop().frames(start): - then = time.time() - if then-start+delay > RENDERER_TIMEOUT: - break - sendframe(frame) - now = time.time() - time.sleep(min(RENDERER_TIMEOUT, delay - (now-then))) diff --git a/host/matelight/renderers.py b/host/matelight/renderers.py deleted file mode 100644 index f507513..0000000 --- a/host/matelight/renderers.py +++ /dev/null @@ -1,154 +0,0 @@ -import time -try: - import re2 as re -except ImportError: - import re -import numpy as np -from PIL import Image -from pixelterm import xtermcolors -from config import * -from font import * - -default_palette = [ - (0x00, 0x00, 0x00), # 0 normal colors - (0xcd, 0x00, 0x00), # 1 - (0x00, 0xcd, 0x00), # 2 - (0xcd, 0xcd, 0x00), # 3 - (0x00, 0x00, 0xee), # 4 - (0xcd, 0x00, 0xcd), # 5 - (0x00, 0xcd, 0xcd), # 6 - (0xe5, 0xe5, 0xe5), # 7 - (0x7f, 0x7f, 0x7f), # 8 bright colors - (0xff, 0x00, 0x00), # 9 - (0x00, 0xff, 0x00), # 10 - (0xff, 0xff, 0x00), # 11 - (0x5c, 0x5c, 0xff), # 12 - (0xff, 0x00, 0xff), # 13 - (0x00, 0xff, 0xff), # 14 - (0xff, 0xff, 0xff)] # 15 -default_colors = (default_palette[8], default_palette[0]) - -class CharGenerator: - def __init__(self, seq=None, lg=None, text=''): - settings = False, False, False, default_colors - if lg: - settings = lg.bold, lg.blink, lg.underscore, (lg.fg, lg.bg) - self.bold, self.blink, self.underscore, (self.fg, self.bg) = settings - self.text = text - if seq: - self.parse_escape_sequence(seq) - - def parse_escape_sequence(self, seq): - codes = list(map(int, seq[2:-1].split(';'))) - fg, bg, reverse, i = self.fg, self.bg, False, 0 - while i