summaryrefslogtreecommitdiff
path: root/src/libs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/Makefile.am2
-rw-r--r--src/libs/txt/Makefile.am3
-rw-r--r--src/libs/txt/txt.c200
-rw-r--r--src/libs/txt/txt.h33
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
© All Rights Reserved