diff options
Diffstat (limited to 'src/libs')
-rw-r--r-- | src/libs/Makefile.am | 2 | ||||
-rw-r--r-- | src/libs/txt/Makefile.am | 3 | ||||
-rw-r--r-- | src/libs/txt/txt.c | 200 | ||||
-rw-r--r-- | src/libs/txt/txt.h | 33 |
4 files changed, 237 insertions, 1 deletions
diff --git a/src/libs/Makefile.am b/src/libs/Makefile.am index 48fb649..e0895ce 100644 --- a/src/libs/Makefile.am +++ b/src/libs/Makefile.am @@ -1 +1 @@ -SUBDIRS = ascii grid ray +SUBDIRS = ascii grid ray txt diff --git a/src/libs/txt/Makefile.am b/src/libs/txt/Makefile.am new file mode 100644 index 0000000..88aa79b --- /dev/null +++ b/src/libs/txt/Makefile.am @@ -0,0 +1,3 @@ +noinst_LIBRARIES = libtxt.a +libtxt_a_SOURCES = txt.c txt.h +libtxt_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/libs/txt/txt.c b/src/libs/txt/txt.c new file mode 100644 index 0000000..e42d8c2 --- /dev/null +++ b/src/libs/txt/txt.c @@ -0,0 +1,200 @@ +#include <assert.h> +#include <stdarg.h> +#include <stdlib.h> + +#include "fb.h" + +#include "ascii/ascii.h" +#include "txt.h" + + +struct txt_t { + int len, width, height; + char str[]; +}; + + +/* compute the rectangle dimensions of the string in rendered pixels */ +static void measure_str(const char *str, int *res_width, int *res_height) +{ + int rows = 1, cols = 0, col = 0; + char c; + + assert(str); + assert(res_width); + assert(res_height); + + while (c = *str) { + switch (c) { + case ' '...'~': + col++; + break; + + case '\n': + if (col > cols) + cols = col; + col = 0; + rows++; + break; + + default: + break; + } + str++; + } + + *res_height = 1 + rows * (ASCII_HEIGHT + 1); + *res_width = 1 + cols * (ASCII_WIDTH + 1); +} + + +txt_t * txt_new(const char *str) +{ + txt_t *txt; + int len; + + assert(str); + + len = strlen(str); + + txt = calloc(1, sizeof(txt_t) + len + 1); + if (!txt) + return NULL; + + txt->len = len; + memcpy(txt->str, str, len); + + measure_str(txt->str, &txt->width, &txt->height); + + return txt; +} + + +txt_t * txt_newf(const char *fmt, ...) +{ + char buf[1024] = {}; /* XXX: it's not expected there will be long strings */ + va_list ap; + + assert(fmt); + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf) - 1, fmt, ap); + va_end(ap); + + return txt_new(buf); +} + + +txt_t * txt_free(txt_t *txt) +{ + free(txt); + + return NULL; +} + + +/* Adjusts x and y according to alignment, width, and height. Returning the adjusted x and y + * in res_x, res_y. + * + * res_x,res_y will be the coordinate of the upper left corner of the rect + * described by width,height when aligned relative to x,y according to the + * specified alignment. + * + * e.g. if an alignment of TXT_HALIGN_LEFT,TXT_VALIGN_TOP is supplied, x,y is returned verbatim + * in res_x,res_y. + * an alignment of TXT_HALIGN_CENTER,TXT_VALIGN_CENTER returns x-width/2 and y-width/2. + */ +static void justify(txt_align_t alignment, int x, int y, unsigned width, unsigned height, int *res_x, int *res_y) +{ + assert(res_x); + assert(res_y); + + switch (alignment.horiz) { + case TXT_HALIGN_CENTER: + x -= width >> 1; + break; + + case TXT_HALIGN_LEFT: + break; + + case TXT_HALIGN_RIGHT: + x -= width; + break; + + default: + assert(0); + } + + switch (alignment.vert) { + case TXT_VALIGN_CENTER: + y -= height >> 1; + break; + + case TXT_VALIGN_TOP: + break; + + case TXT_VALIGN_BOTTOM: + y -= height; + break; + + default: + assert(0); + } + + *res_x = x; + *res_y = y; +} + + +static int overlaps(int x1, int y1, unsigned w1, unsigned h1, int x2, int y2, unsigned w2, unsigned h2) +{ + /* TODO */ + return 1; +} + + +static inline void draw_char(fb_fragment_t *fragment, uint32_t color, int x, int y, char c) +{ + /* TODO: this could be optimized to skip characters with no overlap */ + for (int i = 0; i < ASCII_HEIGHT; i++) { + for (int j = 0; j < ASCII_WIDTH; j++) { + if (ascii_chars[c][i * ASCII_WIDTH + j]) + fb_fragment_put_pixel_checked(fragment, x + j, y + i, color); + } + } +} + + +void txt_render_fragment(txt_t *txt, fb_fragment_t *fragment, uint32_t color, int x, int y, txt_align_t alignment) +{ + int jx, jy, col, row; + char c, *str; + + assert(txt); + assert(fragment); + + justify(alignment, x, y, txt->width, txt->height, &jx, &jy); + + if (!overlaps(jx, jy, txt->width, txt->height, + fragment->x, fragment->y, + fragment->width, fragment->height)) + return; + + + for (col = 0, row = 0, str = txt->str; *str; str++) { + switch (*str) { + case ' '...'~': + draw_char(fragment, color, jx + 1 + col * (ASCII_WIDTH + 1), jy + 1 + row * (ASCII_HEIGHT + 1), *str); + col++; + break; + + case '\n': + col = 0; + row++; + break; + + default: + break; + } + } +} diff --git a/src/libs/txt/txt.h b/src/libs/txt/txt.h new file mode 100644 index 0000000..8c68e30 --- /dev/null +++ b/src/libs/txt/txt.h @@ -0,0 +1,33 @@ +#ifndef _TXT_H +#define _TXT_H + +#include <stdint.h> + +typedef struct fb_fragment_t fb_fragment_t; +typedef struct txt_t txt_t; + +typedef enum txt_halign_t { + TXT_HALIGN_CENTER, + TXT_HALIGN_LEFT, + TXT_HALIGN_RIGHT, + TXT_HALIGN_CNT, +} txt_halign_t; + +typedef enum txt_valign_t { + TXT_VALIGN_CENTER, + TXT_VALIGN_TOP, + TXT_VALIGN_BOTTOM, + TXT_VALIGN_CNT, +} txt_valign_t; + +typedef struct txt_align_t { + txt_halign_t horiz; + txt_valign_t vert; +} txt_align_t; + +txt_t * txt_new(const char *str); +txt_t * txt_newf(const char *fmt, ...); +txt_t * txt_free(txt_t *txt); +void txt_render_fragment(txt_t *txt, fb_fragment_t *fragment, uint32_t color, int x, int y, txt_align_t alignment); + +#endif |