summaryrefslogtreecommitdiff
path: root/src/modules/checkers
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2022-04-19 15:27:30 -0700
committerVito Caputo <vcaputo@pengaru.com>2022-04-22 00:50:39 -0700
commitf8929c9f06eff1dc2efa8331a26fb0f7b1ab3252 (patch)
treecd61010c66eba98513e5741bacff8dcafaf9af3b /src/modules/checkers
parent8e1330d60cb94629cbc09f65f558d47cdbfe633b (diff)
modules/checkers: experimenting with a checkers overlay
This adds a checkers style overlay module, it's not terribly interesting but may be made more useful if modules start differentiating themselves as substantial vs. overlay effects. It'd be nice if rtv/compose could automagically apply and randomize overlay modules atop others, which would make use of this type of thing as well as encourage more small modules like these be written.
Diffstat (limited to 'src/modules/checkers')
-rw-r--r--src/modules/checkers/Makefile.am3
-rw-r--r--src/modules/checkers/checkers.c302
2 files changed, 305 insertions, 0 deletions
diff --git a/src/modules/checkers/Makefile.am b/src/modules/checkers/Makefile.am
new file mode 100644
index 0000000..817e88f
--- /dev/null
+++ b/src/modules/checkers/Makefile.am
@@ -0,0 +1,3 @@
+noinst_LTLIBRARIES = libcheckers.la
+libcheckers_la_SOURCES = checkers.c
+libcheckers_la_CPPFLAGS = -I@top_srcdir@/src
diff --git a/src/modules/checkers/checkers.c b/src/modules/checkers/checkers.c
new file mode 100644
index 0000000..a88f17c
--- /dev/null
+++ b/src/modules/checkers/checkers.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2022 - Vito Caputo - <vcaputo@pengaru.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "til.h"
+#include "til_fb.h"
+
+
+#define CHECKERS_DEFAULT_SIZE 32
+#define CHECKERS_DEFAULT_PATTERN CHECKERS_PATTERN_CHECKERED
+#define CHECKERS_DEFAULT_DYNAMICS CHECKERS_DYNAMICS_ODD
+#define CHECKERS_DEFAULT_DYNAMICS_RATE 1.0
+
+
+typedef enum checkers_pattern_t {
+ CHECKERS_PATTERN_CHECKERED,
+ CHECKERS_PATTERN_RANDOM,
+} checkers_pattern_t;
+
+typedef enum checkers_dynamics_t {
+ CHECKERS_DYNAMICS_ODD,
+ CHECKERS_DYNAMICS_EVEN,
+ CHECKERS_DYNAMICS_ALTERNATING,
+ CHECKERS_DYNAMICS_RANDOM,
+} checkers_dynamics_t;
+
+typedef struct checkers_setup_t {
+ unsigned size;
+ checkers_pattern_t pattern;
+ checkers_dynamics_t dynamics;
+ float rate;
+} checkers_setup_t;
+
+typedef struct checkers_context_t {
+ checkers_setup_t setup;
+} checkers_context_t;
+
+
+static checkers_setup_t checkers_default_setup = {
+ .size = CHECKERS_DEFAULT_SIZE,
+ .pattern = CHECKERS_DEFAULT_PATTERN,
+ .dynamics = CHECKERS_DEFAULT_DYNAMICS,
+ .rate = CHECKERS_DEFAULT_DYNAMICS_RATE,
+};
+
+
+static void * checkers_create_context(unsigned ticks, unsigned num_cpus, void *setup)
+{
+ checkers_context_t *ctxt;
+
+ if (!setup)
+ setup = &checkers_default_setup;
+
+ ctxt = calloc(1, sizeof(checkers_context_t));
+ if (!ctxt)
+ return NULL;
+
+ ctxt->setup = *(checkers_setup_t *)setup;
+
+ return ctxt;
+}
+
+
+static void checkers_destroy_context(void *context)
+{
+ free(context);
+}
+
+
+static int checkers_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment)
+{
+ checkers_context_t *ctxt = context;
+
+ return til_fb_fragment_tile_single(fragment, ctxt->setup.size, number, res_fragment);
+}
+
+
+static void checkers_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter)
+{
+ *res_fragmenter = checkers_fragmenter;
+}
+
+
+static inline unsigned hash(unsigned x)
+{
+ x = ((x >> 16) ^ x) * 0x61C88647;
+ x = ((x >> 16) ^ x) * 0x61C88647;
+ x = ((x >> 16) ^ x) * 0x61C88647;
+ x = (x >> 16) ^ x;
+
+ return x;
+}
+
+
+static void checkers_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment)
+{
+ checkers_context_t *ctxt = context;
+ int state;
+
+ switch (ctxt->setup.pattern) {
+ case CHECKERS_PATTERN_CHECKERED: {
+ unsigned tiles_per_row;
+
+ tiles_per_row = fragment->frame_width / ctxt->setup.size;
+ if (tiles_per_row * ctxt->setup.size < fragment->frame_width)
+ tiles_per_row++;
+
+ state = (fragment->number + (fragment->y / ctxt->setup.size) * !(tiles_per_row & 0x1)) & 0x1;
+ break;
+ }
+ case CHECKERS_PATTERN_RANDOM:
+ state = hash(fragment->number * 0x61C88647) & 0x1;
+ break;
+ }
+
+ switch (ctxt->setup.dynamics) {
+ case CHECKERS_DYNAMICS_ODD:
+ break;
+ case CHECKERS_DYNAMICS_EVEN:
+ state = ~state & 0x1;
+ break;
+ case CHECKERS_DYNAMICS_ALTERNATING:
+ state ^= ((unsigned)((float)ticks * ctxt->setup.rate) & 0x1);
+ break;
+ case CHECKERS_DYNAMICS_RANDOM: /* note: the big multiply here is just to get up out of the low bits */
+ state &= hash(fragment->number * 0x61C88647 + (unsigned)((float)ticks * ctxt->setup.rate)) & 0x1;
+ break;
+ }
+
+ if (!state)
+ til_fb_fragment_clear(fragment);
+ else
+ til_fb_fragment_fill(fragment, 0xffffffff);
+}
+
+
+static int checkers_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, void **res_setup)
+{
+ const char *size;
+ const char *pattern;
+ const char *dynamics;
+ const char *dynamics_rate;
+ const char *size_values[] = {
+ "4",
+ "8",
+ "16",
+ "32",
+ "64",
+ "128",
+ NULL
+ };
+ const char *pattern_values[] = {
+ "checkered",
+ "random",
+ NULL
+ };
+ const char *dynamics_values[] = {
+ "odd",
+ "even",
+ "alternating",
+ "random",
+ NULL
+ };
+ const char *dynamics_rate_values[] = {
+ "1.0",
+ ".75",
+ ".5",
+ ".25",
+ ".1",
+ ".01",
+ ".001",
+ ".0001",
+ NULL
+ };
+ int r;
+
+ r = til_settings_get_and_describe_value(settings,
+ &(til_setting_desc_t){
+ .name = "Checker size",
+ .key = "size",
+ .regex = "\\.[0-9]+",
+ .preferred = TIL_SETTINGS_STR(CHECKERS_DEFAULT_SIZE),
+ .values = size_values,
+ .annotations = NULL
+ },
+ &size,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+
+ r = til_settings_get_and_describe_value(settings,
+ &(til_setting_desc_t){
+ .name = "Checkers pattern",
+ .key = "pattern",
+ .preferred = pattern_values[0],
+ .values = pattern_values,
+ .annotations = NULL
+ },
+ &pattern,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+
+ r = til_settings_get_and_describe_value(settings,
+ &(til_setting_desc_t){
+ .name = "Checkers dynamics",
+ .key = "dynamics",
+ .preferred = dynamics_values[0],
+ .values = dynamics_values,
+ .annotations = NULL
+ },
+ &dynamics,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+
+ if (strcasecmp(dynamics, "odd") && strcasecmp(dynamics, "even")) {
+ r = til_settings_get_and_describe_value(settings,
+ &(til_setting_desc_t){
+ .name = "Checkers dynamics rate",
+ .key = "dynamics_rate",
+ .preferred = dynamics_rate_values[0],
+ .values = dynamics_rate_values,
+ .annotations = NULL
+ },
+ &dynamics_rate,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+ }
+
+ if (res_setup) {
+ checkers_setup_t *setup;
+
+ setup = calloc(1, sizeof(*setup));
+ if (!setup)
+ return -ENOMEM;
+
+ sscanf(size, "%u", &setup->size);
+
+ if (!strcmp(pattern, "checkered"))
+ setup->pattern = CHECKERS_PATTERN_CHECKERED;
+ else if (!strcmp(pattern, "random"))
+ setup->pattern = CHECKERS_PATTERN_RANDOM;
+ else {
+ free(setup);
+ return -EINVAL;
+ }
+
+ if (!strcmp(dynamics, "odd"))
+ setup->dynamics = CHECKERS_DYNAMICS_ODD;
+ else if (!strcmp(dynamics, "even"))
+ setup->dynamics = CHECKERS_DYNAMICS_EVEN;
+ else if (!strcmp(dynamics, "alternating"))
+ setup->dynamics = CHECKERS_DYNAMICS_ALTERNATING;
+ else if (!strcmp(dynamics, "random"))
+ setup->dynamics = CHECKERS_DYNAMICS_RANDOM;
+ else {
+ free(setup);
+ return -EINVAL;
+ }
+
+ if (setup->dynamics != CHECKERS_DYNAMICS_ODD && setup->dynamics != CHECKERS_DYNAMICS_EVEN)
+ sscanf(dynamics_rate, "%f", &setup->rate);
+
+ *res_setup = setup;
+ }
+
+ return 0;
+}
+
+
+til_module_t checkers_module = {
+ .create_context = checkers_create_context,
+ .destroy_context = checkers_destroy_context,
+ .prepare_frame = checkers_prepare_frame,
+ .render_fragment = checkers_render_fragment,
+ .name = "checkers",
+ .description = "Checker-patterned overlay (threaded)",
+ .author = "Vito Caputo <vcaputo@pengaru.com>",
+ .setup = checkers_setup,
+};
© All Rights Reserved