diff options
Diffstat (limited to 'src/modules/asc')
-rw-r--r-- | src/modules/asc/Makefile.am | 3 | ||||
-rw-r--r-- | src/modules/asc/asc.c | 231 |
2 files changed, 234 insertions, 0 deletions
diff --git a/src/modules/asc/Makefile.am b/src/modules/asc/Makefile.am new file mode 100644 index 0000000..c9f7a6e --- /dev/null +++ b/src/modules/asc/Makefile.am @@ -0,0 +1,3 @@ +noinst_LTLIBRARIES = libasc.la +libasc_la_SOURCES = asc.c +libasc_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/asc/asc.c b/src/modules/asc/asc.c new file mode 100644 index 0000000..2d50021 --- /dev/null +++ b/src/modules/asc/asc.c @@ -0,0 +1,231 @@ +#include <errno.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "til.h" +#include "til_fb.h" +#include "til_module_context.h" + +#include "txt/txt.h" + +/* Copyright (C) 2023 Vito Caputo <vcaputo@pengaru.com> */ + +/* This is intended primarily for diagnostic purposes or as a stand-in you'd eventually + * replace with something a more visually interesting font/style. + * + * TODO: + * - Wire up taps for the x/y coordinates, making this a handy taps diagnostic + * + * - Maybe add a dynamic justification mode where the h/v alignment offsets are + * just the inverse of the normalized x/y coordinates. This requires extending + * libs/txt to support precise offsetting when rendering as an alternative to the + * enum'd txt_align_t variant. But it would allow a tapped x/y coordinate user to + * sweep the coordinates edge-to-edge with the text smoothly adjusting its offset + * throughout the sweep so it doesn't extend off-screen at the nearest edge. + */ + +#define ASC_DEFAULT_STRING "Hello rototiller!" +#define ASC_DEFAULT_HALIGN TXT_HALIGN_CENTER +#define ASC_DEFAULT_VALIGN TXT_VALIGN_CENTER +#define ASC_DEFAULT_X 0 +#define ASC_DEFAULT_Y 0 + + +typedef struct asc_setup_t { + til_setup_t til_setup; + + const char *string; + txt_halign_t halign; + txt_valign_t valign; + float x, y; +} asc_setup_t; + +typedef struct asc_context_t { + til_module_context_t til_module_context; + + txt_t *txt; +} asc_context_t; + + +static til_module_context_t * asc_create_context(const til_module_t *module, til_stream_t *stream, unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup) +{ + asc_context_t *ctxt; + + ctxt = til_module_context_new(module, sizeof(asc_context_t), stream, seed, ticks, n_cpus, setup); + if (!ctxt) + return NULL; + + ctxt->txt = txt_new(((asc_setup_t *)setup)->string); + if (!ctxt->txt) + return til_module_context_free(&ctxt->til_module_context); + + return &ctxt->til_module_context; +} + + +static void asc_render_fragment(til_module_context_t *context, til_stream_t *stream, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr) +{ + asc_context_t *ctxt = (asc_context_t *)context; + asc_setup_t *s = (asc_setup_t *)context->setup; + til_fb_fragment_t *fragment = *fragment_ptr; + + til_fb_fragment_clear(fragment); + + txt_render_fragment(ctxt->txt, fragment, 0xffffffff, + s->x * ((float)fragment->frame_width) * .5f + .5f * ((float)fragment->frame_width), + s->y * ((float)fragment->frame_height) * .5f + .5f * ((float)fragment->frame_height), + (txt_align_t){ + .horiz = s->halign, + .vert = s->valign + }); +} + + +static void asc_setup_free(til_setup_t *setup) +{ + asc_setup_t *s = (asc_setup_t *)setup; + + if (s) { + free((void *)s->string); + free(s); + } +} + + +static int asc_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup); + + +til_module_t asc_module = { + .create_context = asc_create_context, + .render_fragment = asc_render_fragment, + .setup = asc_setup, + .name = "asc", + .description = "ASCII text", + .author = "Vito Caputo <vcaputo@pengaru.com>", + .flags = TIL_MODULE_OVERLAYABLE, +}; + + +static int asc_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup) +{ + til_setting_t *string; + til_setting_t *valign; + til_setting_t *halign; + til_setting_t *x, *y; + const char *valign_values[] = { + "center", + "top", + "bottom", + NULL + }; + const char *halign_values[] = { + "center", + "left", + "right", + NULL + }; + int r; + + r = til_settings_get_and_describe_setting(settings, + &(til_setting_spec_t){ + .name = "Text string", + .key = "string", + /* .regex = "" TODO */ + .preferred = ASC_DEFAULT_STRING, + }, + &string, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_setting(settings, + &(til_setting_spec_t){ + .name = "Vertical alignment", + .key = "valign", + /* .regex = "" TODO */ + .preferred = valign_values[ASC_DEFAULT_VALIGN], + .values = valign_values, + .annotations = NULL + }, + &valign, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_setting(settings, + &(til_setting_spec_t){ + .name = "Horizontal alignment", + .key = "halign", + /* .regex = "" TODO */ + .preferred = halign_values[ASC_DEFAULT_HALIGN], + .values = halign_values, + .annotations = NULL + }, + &halign, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_setting(settings, + &(til_setting_spec_t){ + .name = "X coordinate [-1.0...1.0]", + .key = "x", + /* .regex = "" TODO */ + .preferred = TIL_SETTINGS_STR(ASC_DEFAULT_X), + .annotations = NULL + }, + &x, + res_setting, + res_desc); + if (r) + return r; + + r = til_settings_get_and_describe_setting(settings, + &(til_setting_spec_t){ + .name = "Y coordinate [-1.0...1.0]", + .key = "y", + /* .regex = "" TODO */ + .preferred = TIL_SETTINGS_STR(ASC_DEFAULT_Y), + .annotations = NULL + }, + &y, + res_setting, + res_desc); + if (r) + return r; + + if (res_setup) { + asc_setup_t *setup; + + setup = til_setup_new(settings, sizeof(*setup), asc_setup_free, &asc_module); + if (!setup) + return -ENOMEM; + + setup->string = strdup(string->value); + if (!setup->string) + return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, string, res_setting, -ENOMEM); + + r = til_value_to_pos(halign_values, halign->value, (unsigned *)&setup->halign); + if (r < 0) + return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, halign, res_setting, -EINVAL); + + r = til_value_to_pos(valign_values, valign->value, (unsigned *)&setup->valign); + if (r < 0) + return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, valign, res_setting, -EINVAL); + + if (sscanf(x->value, "%f", &setup->x) != 1) + return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, x, res_setting, -EINVAL); + + if (sscanf(y->value, "%f", &setup->y) != 1) + return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, y, res_setting, -EINVAL); + + *res_setup = &setup->til_setup; + } + + return 0; +} |