diff options
-rw-r--r-- | host/Makefile | 4 | ||||
-rw-r--r-- | host/bdf.c (renamed from host/main.c) | 82 | ||||
-rw-r--r-- | host/bdf.h | 11 | ||||
-rw-r--r-- | host/font.c | 14 | ||||
-rw-r--r-- | host/font.h | 2 | ||||
-rw-r--r-- | host/main.h | 10 | ||||
-rwxr-xr-x | host/server.py | 51 |
7 files changed, 89 insertions, 85 deletions
diff --git a/host/Makefile b/host/Makefile index 8abc88a..85536f5 100644 --- a/host/Makefile +++ b/host/Makefile @@ -5,8 +5,8 @@ all: libml libbdf libml: usb.c color.c color.h gcc -shared -fPIC -std=gnu11 -Wall -lm -lusb-1.0 -o libml.so -g usb.c color.c -libbdf: main.c font.c font.h color.c color.h - gcc -shared -fPIC -std=gnu11 -Wall -lm -o libbdf.so -g main.c font.c color.c +libbdf: bdf.c font.c font.h color.c color.h + gcc -shared -fPIC -std=gnu11 -Wall -lm -o libbdf.so -g bdf.c font.c color.c clean: rm libbdf.so libml.so @@ -1,6 +1,6 @@ #include "config.h" -#include "main.h" +#include "bdf.h" #include "color.h" #include "font.h" #include <stdint.h> @@ -17,20 +17,11 @@ #include <netinet/in.h> #include <unistd.h> - -void free_framebuffer(framebuffer_t *fb){ - free(fb->data); - free(fb); -} - /* CAUTION: REQUIRES INPUT TO BE \0-TERMINATED * ...also, it does a hardcoded setlocale of LC_CTYPE to en_US.utf8 for... reasons. */ -framebuffer_t *framebuffer_render_text(char *s, glyphtable_t *glyph_table){ - unsigned int len = strlen(s); - - color_t *gbuf = NULL; - unsigned int gbufwidth = 0; - unsigned int gbufheight = 0; +int framebuffer_get_text_bounds(char *s, glyphtable_t *glyph_table, size_t *outw, size_t *outh){ + size_t gbufwidth = 0; + size_t gbufheight = 0; char *p = s; /* Calculate screen width of string prior to allocating memory for the frame buffer */ @@ -80,19 +71,31 @@ framebuffer_t *framebuffer_render_text(char *s, glyphtable_t *glyph_table){ gbufwidth += g->width; } - /* For easier rendering on the terminal, round up to multiples of two */ - gbufheight += gbufheight&1; + *outw = gbufwidth; + *outh = gbufheight; + return 0; +error: + return 1; +} + +/* CAUTION: REQUIRES INPUT TO BE \0-TERMINATED + * ...also, it does a hardcoded setlocale of LC_CTYPE to en_US.utf8 for... reasons. */ +/* Render the string beginning from the specified x offset (in pixels) */ +int framebuffer_render_text(char *s, glyphtable_t *glyph_table, color_t *gbuf, size_t gbufwidth, size_t gbufheight, size_t offx){ + unsigned int len = strlen(s); + char *p = s; - size_t gbufsize = gbufwidth*gbufheight; - gbuf = calloc(gbufsize, sizeof(color_t)); - if(!gbuf){ - fprintf(stderr, "Cannot malloc() %zu bytes.\n", gbufsize*sizeof(color_t)); + if(!setlocale(LC_CTYPE, "en_US.utf8")){ + fprintf(stderr, "Cannot set locale\n"); goto error; } - memset(gbuf, 0, gbufsize*sizeof(color_t)); + + memset(gbuf, 0, gbufwidth*gbufheight*sizeof(color_t)); unsigned int x = 0; + wchar_t c; p = s; + mbstate_t ps = {0}; memset(&ps, 0, sizeof(mbstate_t)); struct { color_t fg; @@ -279,32 +282,29 @@ framebuffer_t *framebuffer_render_text(char *s, glyphtable_t *glyph_table){ color_t bg = inv ? style.bg : style.fg; glyph_t *g = glyph_table->data[c]; - render_glyph(g, gbuf, gbufwidth, x, 0, fg, bg); - if(style.strikethrough || style.underline){ - int sty = gbufheight/2; - /* g->y 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; i<g->width; i++){ - if(style.strikethrough) - gbuf[sty*gbufwidth + x + i] = fg; - if(style.underline) - gbuf[uly*gbufwidth + x + i] = fg; + /* Is the glyph within the buffer's bounds? */ + if(x+g->width > offx && x < offx+gbufwidth){ + /* x-offx might be negative down to -g->width+1, but that's ok */ + render_glyph(g, gbuf, gbufwidth, x-offx, 0, fg, bg); + if(style.strikethrough || style.underline){ + int sty = gbufheight/2; + /* g->y 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; i<g->width; i++){ + if(x+i >= offx){ /* Stay within the frame buffer's bounds */ + if(style.strikethrough) + gbuf[sty*gbufwidth + x + i - offx] = fg; + if(style.underline) + gbuf[uly*gbufwidth + x + i - offx] = fg; + } + } } } x += g->width; } - framebuffer_t *fb = malloc(sizeof(framebuffer_t)); - if(!fb){ - fprintf(stderr, "Cannot malloc() %zu bytes.\n", sizeof(framebuffer_t)); - goto error; - } - fb->w = gbufwidth; - fb->h = gbufheight; - fb->data = gbuf; - return fb; -error: - free(gbuf); return 0; +error: + return 1; } void console_render_buffer(color_t *data, size_t w, size_t h){ diff --git a/host/bdf.h b/host/bdf.h new file mode 100644 index 0000000..c81277e --- /dev/null +++ b/host/bdf.h @@ -0,0 +1,11 @@ +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#include "color.h" +#include "font.h" + +int framebuffer_get_text_bounds(char *s, glyphtable_t *glyph_table, size_t *outw, size_t *outh); +int framebuffer_render_text(char *s, glyphtable_t *glyph_table, color_t *gbuf, size_t gbufwidth, size_t gbufheight, size_t offx); +void console_render_buffer(color_t *data, size_t w, size_t h); + +#endif//__MAIN_H__ diff --git a/host/font.c b/host/font.c index ee9adb3..c1f1d22 100644 --- a/host/font.c +++ b/host/font.c @@ -6,7 +6,8 @@ #include <string.h> #include <errno.h> -void render_glyph(glyph_t *g, color_t *buf, unsigned int bufwidth, unsigned int offx, unsigned int offy, color_t fg, color_t bg){ +/* Clips at buffer bounds */ +void render_glyph(glyph_t *g, color_t *buf, unsigned int bufwidth, 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,10 +17,13 @@ void render_glyph(glyph_t *g, color_t *buf, unsigned int bufwidth, unsigned int data |= bitmap[y*bitmap_row_width+i]; } color_t *p = buf + (offy+y)*bufwidth + offx; - for(unsigned int x=0; x < g->width; x++){ - color_t c = (data&(1<<(g->width-1))) ? fg : bg; - *p++ = c; - data <<= 1; + /* Take care to only render what's within the framebuffer's bounds */ + for(unsigned int x=0; (x < g->width) && (offx+x < bufwidth); x++){ + if(offx + x >= 0){ + color_t c = (data&(1<<(g->width-1))) ? fg : bg; + *p++ = c; + data <<= 1; + } } } } diff --git a/host/font.h b/host/font.h index e9fbb35..ad7f851 100644 --- a/host/font.h +++ b/host/font.h @@ -30,6 +30,6 @@ glyphtable_t *read_bdf(FILE *f); void free_glyphtable(glyphtable_t *glyph_table); // Requires buf to point to a buffer at least of size glyph->width*glyph->height. -void render_glyph(glyph_t *glyph, color_t *buf, unsigned int bufwidth, unsigned int offx, unsigned int offy, color_t fg, color_t bg); +void render_glyph(glyph_t *g, color_t *buf, unsigned int bufwidth, int offx, unsigned int offy, color_t fg, color_t bg); #endif//__FONT_H__ diff --git a/host/main.h b/host/main.h deleted file mode 100644 index 5ace45e..0000000 --- a/host/main.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __MAIN_H__ -#define __MAIN_H__ - -#include "color.h" -#include "font.h" - -framebuffer_t *framebuffer_render_text(char *s, glyphtable_t *glyph_table); -void console_render_buffer(color_t *data, size_t w, size_t h); - -#endif//__MAIN_H__ diff --git a/host/server.py b/host/server.py index 56002fa..679b13b 100755 --- a/host/server.py +++ b/host/server.py @@ -7,7 +7,7 @@ from itertools import product, cycle import threading import random -from ctypes import CDLL, POINTER, c_void_p, Structure, c_uint8, c_size_t, cast, addressof +from ctypes import * import numpy as np @@ -26,20 +26,26 @@ class FRAMEBUFFER(Structure): bdf = CDLL('./libbdf.so') bdf.read_bdf_file.restype = c_void_p bdf.framebuffer_render_text.restype = POINTER(FRAMEBUFFER) +bdf.framebuffer_render_text.argtypes= [c_char_p, c_void_p, c_void_p, c_size_t, c_size_t, c_size_t] unifont = bdf.read_bdf_file('unifont.bdf') -def render_text(text): +def compute_text_bounds(text): assert unifont - fb = bdf.framebuffer_render_text(bytes(str(text), 'UTF-8'), unifont) - fbd = fb.contents - buf = np.ctypeslib.as_array(cast(fbd.data, POINTER(c_uint8)), shape=(fbd.h, fbd.w, 4)) - # Set data pointer to NULL before freeing framebuffer struct to prevent free_framebuffer from also freeing the data - # buffer that is now used by numpy - #bdf.console_render_buffer(fb) - fbd.data = cast(c_void_p(), POINTER(COLOR)) - bdf.free_framebuffer(fb) - return buf + textbytes = bytes(str(text), 'UTF-8') + textw, texth = c_size_t(0), c_size_t(0) + res = bdf.framebuffer_get_text_bounds(textbytes, unifont, byref(textw), byref(texth)) + if res: + raise ValueError('Invalid text') + return textw.value, texth.value + +def render_text(text, offset): + cbuf = create_string_buffer(FRAME_SIZE*sizeof(COLOR)) + textbytes = bytes(str(text), 'UTF-8') + res = bdf.framebuffer_render_text(textbytes, unifont, cbuf, DISPLAY_WIDTH, DISPLAY_HEIGHT, offset) + if res: + raise ValueError('Invalid text') + return np.ctypeslib.as_array(cast(cbuf, POINTER(c_uint8)), shape=(DISPLAY_WIDTH, DISPLAY_HEIGHT, 4)) printlock = threading.Lock() @@ -55,19 +61,11 @@ def printframe(fb): def scroll(text): """ Returns whether it could scroll all the text uninterrupted """ log('Scrolling', text) - fb = render_text(text); - h,w,_ = fb.shape + w,h = compute_text_bounds(text) for i in range(-DISPLAY_WIDTH,w+1): -# if current_entry.entrytype == 'udp' or (textqueue and current_entry in defaulttexts): -# log('Aborting rendering due to new input') -# return False - leftpad = np.zeros((DISPLAY_HEIGHT, max(-i, 0), 4), dtype=np.uint8) - framedata = fb[:, max(0, i):min(i+DISPLAY_WIDTH, w)] - rightpad = np.zeros((DISPLAY_HEIGHT, min(DISPLAY_WIDTH, max(0, i+DISPLAY_WIDTH-w)), 4), dtype=np.uint8) - dice = np.concatenate((leftpad, framedata, rightpad), 1) - sendframe(dice) - printframe(dice) - fb = render_text(text); + fb = render_text(text, i); + sendframe(fb) + printframe(fb) return True QueueEntry = namedtuple('QueueEntry', ['entrytype', 'remote', 'timestamp', 'text']) @@ -80,7 +78,7 @@ textqueue = [] def log(*args): printlock.acquire() - print(strftime('[%m-%d %H:%M:%S]'), ' '.join(str(arg) for arg in args), '\x1B[0m') + print(strftime('\x1B[93m[%m-%d %H:%M:%S]\x1B[0m'), ' '.join(str(arg) for arg in args), '\x1B[0m') printlock.release() class MateLightUDPHandler(BaseRequestHandler): @@ -107,7 +105,7 @@ class MateLightUDPHandler(BaseRequestHandler): addr = self.client_address[0] conn = QueueEntry('udp', addr, timestamp, '') if addr not in conns: - log('New UDP connection from', addr) + log('\x1B[91mNew UDP connection from\x1B[0m', addr) current_entry = conn conns[addr] = current_entry if current_entry.entrytype == 'udp' and current_entry.remote == addr: @@ -127,7 +125,7 @@ class MateLightTCPTextHandler(BaseRequestHandler): if len(data) > 140: self.request.sendall('TOO MUCH INFORMATION!\n') return - log('Text from {}: {}\x1B[0m'.format(addr, data)) + log('\x1B[95mText from\x1B[0m {}: {}\x1B[0m'.format(addr, data)) textqueue.append(QueueEntry('text', addr, timestamp, data)) self.request.sendall(b'KTHXBYE!\n') @@ -159,6 +157,7 @@ if __name__ == '__main__': current_entry = next(defaulttexts) if current_entry.entrytype != 'udp' and textqueue: current_entry = textqueue[0] + log('\x1B[92mScrolling\x1B[0m', current_entry.text) if current_entry.entrytype == 'udp': if time() - current_entry.timestamp > UDP_TIMEOUT: current_entry = next(defaulttexts) |