diff options
Diffstat (limited to 'src/modules')
-rw-r--r-- | src/modules/Makefile.am | 2 | ||||
-rw-r--r-- | src/modules/moire/Makefile.am | 3 | ||||
-rw-r--r-- | src/modules/moire/moire.c | 173 |
3 files changed, 177 insertions, 1 deletions
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index d00ac7b..83adbc5 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -1 +1 @@ -SUBDIRS = blinds checkers compose drizzle flui2d julia meta2d 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 submit swab swarm voronoi diff --git a/src/modules/moire/Makefile.am b/src/modules/moire/Makefile.am new file mode 100644 index 0000000..9d72068 --- /dev/null +++ b/src/modules/moire/Makefile.am @@ -0,0 +1,3 @@ +noinst_LTLIBRARIES = libmoire.la +libmoire_la_SOURCES = moire.c +libmoire_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/moire/moire.c b/src/modules/moire/moire.c new file mode 100644 index 0000000..1678170 --- /dev/null +++ b/src/modules/moire/moire.c @@ -0,0 +1,173 @@ +/* + * 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 <math.h> +#include <stdlib.h> +#include <unistd.h> + +#include "til.h" +#include "til_fb.h" +#include "til_module_context.h" + +#define MOIRE_DEFAULT_CENTERS 2 + +typedef struct moire_setup_t { + til_setup_t til_setup; + unsigned n_centers; +} moire_setup_t; + +typedef struct moire_center_t { + float x, y; + float seed; + float dir; +} moire_center_t; + +typedef struct moire_context_t { + til_module_context_t til_module_context; + moire_setup_t setup; + moire_center_t centers[]; +} moire_context_t; + +static moire_setup_t moire_default_setup = { + .n_centers = MOIRE_DEFAULT_CENTERS, +}; + + +static til_module_context_t * moire_create_context(unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup) +{ + moire_context_t *ctxt; + + if (!setup) + setup = &moire_default_setup.til_setup; + + ctxt = til_module_context_new(sizeof(moire_context_t) + ((moire_setup_t *)setup)->n_centers * sizeof(moire_center_t), seed, n_cpus); + if (!ctxt) + return NULL; + + ctxt->setup = *(moire_setup_t *)setup; + + for (unsigned i = 0; i < ((moire_setup_t *)setup)->n_centers; i++) { + ctxt->centers[i].seed = rand_r(&seed) * (1.f / (float)RAND_MAX) * 2 * M_PI; + ctxt->centers[i].dir = (rand_r(&seed) * (2.f / (float)RAND_MAX) - 1.f); + ctxt->centers[i].x = cosf(ctxt->centers[i].seed + (float)ticks * .001f * ctxt->centers[i].dir); + ctxt->centers[i].y = sinf(ctxt->centers[i].seed + (float)ticks * .001f * ctxt->centers[i].dir); + } + + return &ctxt->til_module_context; +} + + +static void moire_prepare_frame(til_module_context_t *context, unsigned ticks, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) +{ + moire_context_t *ctxt = (moire_context_t *)context; + + *res_fragmenter = til_fragmenter_slice_per_cpu; + + for (unsigned i = 0; i < ctxt->setup.n_centers; i++) { + ctxt->centers[i].x = cosf(ctxt->centers[i].seed + (float)ticks * .001f * ctxt->centers[i].dir); + ctxt->centers[i].y = sinf(ctxt->centers[i].seed + (float)ticks * .001f * ctxt->centers[i].dir); + } +} + + +static void moire_render_fragment(til_module_context_t *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) +{ + moire_context_t *ctxt = (moire_context_t *)context; + float xf = 2.f / (float)fragment->frame_width; + float yf = 2.f / (float)fragment->frame_height; + float cx, cy; + + /* TODO: optimize */ + cy = yf * (float)fragment->y - 1.f; + for (int y = fragment->y; y < fragment->y + fragment->height; y++, cy += yf) { + + cx = xf * (float)fragment->x - 1.f; + for (int x = fragment->x; x < fragment->x + fragment->width; x++, cx += xf) { + int filled = 0; + + for (unsigned i = 0; i < ctxt->setup.n_centers; i++) { + float dx, dy; + + dx = cx - ctxt->centers[i].x; + dy = cy - ctxt->centers[i].y; + + if (cosf(sqrtf(dx * dx + dy * dy) * 50.f) < 0.f) + filled ^= 1; + } + + if (filled) + til_fb_fragment_put_pixel_unchecked(fragment, TIL_FB_DRAW_FLAG_TEXTURABLE, x, y, 0xffffffff); + else if (!fragment->cleared) + til_fb_fragment_put_pixel_unchecked(fragment, 0, x, y, 0x00000000); + } + } +} + + +static int moire_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 *centers; + const char *values[] = { + "2", + "3", + "4", + "5", + NULL + }; + int r; + + r = til_settings_get_and_describe_value(settings, + &(til_setting_desc_t){ + .name = "Number of radial centers", + .key = "centers", + .regex = "\\.[0-9]+", + .preferred = TIL_SETTINGS_STR(MOIRE_DEFAULT_CENTERS), + .values = values, + .annotations = NULL + }, + ¢ers, + res_setting, + res_desc); + if (r) + return r; + + if (res_setup) { + moire_setup_t *setup; + + setup = til_setup_new(sizeof(*setup), (void(*)(til_setup_t *))free); + if (!setup) + return -ENOMEM; + + sscanf(centers, "%u", &setup->n_centers); + + *res_setup = &setup->til_setup; + } + + return 0; +} + + +til_module_t moire_module = { + .create_context = moire_create_context, + .prepare_frame = moire_prepare_frame, + .render_fragment = moire_render_fragment, + .setup = moire_setup, + .name = "moire", + .description = "2D Moire interference patterns (threaded)", + .author = "Vito Caputo <vcaputo@pengaru.com>", + .flags = TIL_MODULE_OVERLAYABLE, +}; |