From b4c9935b5d167ca2ef69b5a6a81ae207f462b45c Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Sun, 4 Sep 2022 23:32:55 -0700 Subject: modules/strobe: add rudimentary strobe light module After reading about the Dreamachine[0], I wanted to experience this phenomenon. The javascript-based web implementations struggled to hold a steady 10Hz rate and would flicker like crazy, so here we are. Only setting right now is period=float_seconds, defaults to .1 for 10Hz. One limitation in the current implementation is when the frame rate can't keep up with the period the strobe will just stick on without ever going off, because the period will always be expired. There should probably be a setting to force turning off for at least one frame when it can't keep up. [0] https://en.wikipedia.org/wiki/Dreamachine --- src/modules/Makefile.am | 2 +- src/modules/strobe/Makefile.am | 3 + src/modules/strobe/strobe.c | 155 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/modules/strobe/Makefile.am create mode 100644 src/modules/strobe/strobe.c (limited to 'src/modules') diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index 83adbc5..f88879e 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -1 +1 @@ -SUBDIRS = blinds checkers compose drizzle flui2d julia meta2d moire montage pixbounce plasma plato ray roto rtv shapes snow sparkler spiro stars submit swab swarm voronoi +SUBDIRS = blinds checkers compose drizzle flui2d julia meta2d moire montage pixbounce plasma plato ray roto rtv shapes snow sparkler spiro stars strobe submit swab swarm voronoi diff --git a/src/modules/strobe/Makefile.am b/src/modules/strobe/Makefile.am new file mode 100644 index 0000000..8bac057 --- /dev/null +++ b/src/modules/strobe/Makefile.am @@ -0,0 +1,3 @@ +noinst_LTLIBRARIES = libstrobe.la +libstrobe_la_SOURCES = strobe.c +libstrobe_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/strobe/strobe.c b/src/modules/strobe/strobe.c new file mode 100644 index 0000000..4616df4 --- /dev/null +++ b/src/modules/strobe/strobe.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include + +#include "til.h" +#include "til_fb.h" +#include "til_module_context.h" + +/* Dead-simple strobe light, initially made to try simulate this contraption: + * https://en.wikipedia.org/wiki/Dreamachine + * + * But it might actually have some general utility in compositing. + */ + +/* Copyright (C) 2022 Vito Caputo */ + +/* TODO: + * - Make period setting more flexible + * - Currently if the frame rate can't keep up with the period, strobe will + * just stick on. There should probably be a force_flash={yes,no} setting + * to ensure a flash still occurs when the frame rate can't keep up. + */ + +#define STROBE_DEFAULT_PERIOD .1 + +typedef struct strobe_setup_t { + til_setup_t til_setup; + float period; +} strobe_setup_t; + +typedef struct strobe_context_t { + til_module_context_t til_module_context; + strobe_setup_t setup; + unsigned ticks; + unsigned flash:1; +} strobe_context_t; + + +static strobe_setup_t strobe_default_setup = { + .period = STROBE_DEFAULT_PERIOD, +}; + + +static til_module_context_t * strobe_create_context(unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup) +{ + strobe_context_t *ctxt; + + if (!setup) + setup = &strobe_default_setup.til_setup; + + ctxt = til_module_context_new(sizeof(strobe_context_t), seed, ticks, n_cpus); + if (!ctxt) + return NULL; + + ctxt->setup = *(strobe_setup_t *)setup; + ctxt->ticks = ticks; + + return &ctxt->til_module_context; +} + + +static void strobe_prepare_frame(til_module_context_t *context, unsigned ticks, til_fb_fragment_t **fragment_ptr, til_frame_plan_t *res_frame_plan) +{ + strobe_context_t *ctxt = (strobe_context_t *)context; + + *res_frame_plan = (til_frame_plan_t){ .fragmenter = til_fragmenter_slice_per_cpu }; + + if (ticks - ctxt->ticks >= (unsigned)(ctxt->setup.period * 1000.f)) + ctxt->flash = 1; +} + + +static void strobe_render_fragment(til_module_context_t *context, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr) +{ + strobe_context_t *ctxt = (strobe_context_t *)context; + til_fb_fragment_t *fragment = *fragment_ptr; + + if (!ctxt->flash) + return til_fb_fragment_clear(fragment); + + til_fb_fragment_fill(fragment, TIL_FB_DRAW_FLAG_TEXTURABLE, 0xffffffff); +} + + +static void strobe_finish_frame(til_module_context_t *context, unsigned int ticks, til_fb_fragment_t **fragment_ptr) +{ + strobe_context_t *ctxt = (strobe_context_t *)context; + + if (!ctxt->flash) + return; + + ctxt->flash = 0; + ctxt->ticks = ticks; +} + + +static int strobe_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup) +{ + const char *period; + const char *period_values[] = { + ".0166", + ".02", + ".025", + ".05", + ".1", + ".25", + ".5", + "1", + NULL + }; + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Strobe period", + .key = "period", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(STROBE_DEFAULT_PERIOD), + .values = period_values, + .annotations = NULL + }, + &period, + res_setting, + res_desc); + if (r) + return r; + + if (res_setup) { + strobe_setup_t *setup; + + setup = til_setup_new(sizeof(*setup), (void(*)(til_setup_t *))free); + if (!setup) + return -ENOMEM; + + sscanf(period, "%f", &setup->period); + + *res_setup = &setup->til_setup; + } + + return 0; +} + + +til_module_t strobe_module = { + .create_context = strobe_create_context, + .prepare_frame = strobe_prepare_frame, + .render_fragment = strobe_render_fragment, + .finish_frame = strobe_finish_frame, + .setup = strobe_setup, + .name = "strobe", + .description = "Strobe light (threaded)", + .author = "Vito Caputo ", + .flags = TIL_MODULE_OVERLAYABLE, +}; -- cgit v1.2.3