diff options
-rw-r--r-- | src/modules/compose/compose.c | 304 |
1 files changed, 207 insertions, 97 deletions
diff --git a/src/modules/compose/compose.c b/src/modules/compose/compose.c index 376fae4..60431f6 100644 --- a/src/modules/compose/compose.c +++ b/src/modules/compose/compose.c @@ -28,7 +28,6 @@ typedef struct compose_layer_t { const til_module_t *module; til_module_context_t *module_ctxt; - char *settings; } compose_layer_t; typedef struct compose_context_t { @@ -40,11 +39,16 @@ typedef struct compose_context_t { compose_layer_t layers[]; } compose_context_t; +typedef struct compose_setup_layer_t { + char *module; + til_setup_t *setup; +} compose_setup_layer_t; + typedef struct compose_setup_t { til_setup_t til_setup; - char *texture; + compose_setup_layer_t texture; size_t n_layers; - char *layers[]; + compose_setup_layer_t layers[]; } compose_setup_t; static til_module_context_t * compose_create_context(const til_module_t *module, til_stream_t *stream, unsigned seed, unsigned ticks, unsigned n_cpus, char *path, til_setup_t *setup); @@ -52,10 +56,6 @@ static void compose_destroy_context(til_module_context_t *context); static void compose_render_fragment(til_module_context_t *context, til_stream_t *stream, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr); static int compose_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup); -static compose_setup_t compose_default_setup = { - .layers = { "drizzle", "stars", "spiro", "plato", NULL }, -}; - til_module_t compose_module = { .create_context = compose_create_context, @@ -69,40 +69,62 @@ til_module_t compose_module = { static til_module_context_t * compose_create_context(const til_module_t *module, til_stream_t *stream, unsigned seed, unsigned ticks, unsigned n_cpus, char *path, til_setup_t *setup) { + compose_setup_t *s = (compose_setup_t *)setup; + size_t layers_path_len; + char *layers_path; compose_context_t *ctxt; - size_t n; - if (!setup) - setup = &compose_default_setup.til_setup; + assert(setup); - for (n = 0; ((compose_setup_t *)setup)->layers[n]; n++); - - ctxt = til_module_context_new(module, sizeof(compose_context_t) + n * sizeof(compose_layer_t), stream, seed, ticks, n_cpus, path, setup); + ctxt = til_module_context_new(module, sizeof(compose_context_t) + s->n_layers * sizeof(compose_layer_t), stream, seed, ticks, n_cpus, path, setup); if (!ctxt) return NULL; - for (size_t i = 0; i < n; i++) { - const til_module_t *layer_module; - til_setup_t *layer_setup = NULL; + layers_path_len = snprintf(NULL, 0, "%s/%s", path, "layers") + 1; + layers_path = calloc(1, layers_path_len); + /* FIXME TODO: path allocation/construction needs revisiting something fierce: + * 1. Layers can have the same module recur, using compose/layers/$modname will just collide. + * 2. We don't want to be ad-hoc constructing these things like this, but I'm deliberately leaving it ridiculous for now. + * 3. Giving the til_setup_t a settings-instance-derived path might Just Fix Everything and eliminate the need for passing around a path altogether: + * + * In scenarios like layers the settings code already generate instance labels in an enumerated array subscript fashion, so the path would be: + * compose/layers/layers[N] + * + * Some things need to change before that happens though, for starters always creating and supplying a til_setup_t to modules even ones without + * a .setup() method would be necessary. Also there isn't a trivial way to take an arbitrary settings instance anywhere in the heirarchy and + * ask til_settings to generate its path - there are no parent pointers going up the tree to construct it in reverse, and the instances don't + * get a full path copy placed into them at creation time, only the label. The label could be changed to an absolute path though, which would + * really be fine since these things don't move around the heirarchy, they just stay where they were created. + */ + if (!layers_path) + return til_module_context_free(&ctxt->til_module_context); - layer_module = til_lookup_module(((compose_setup_t *)setup)->layers[i]); - (void) til_module_randomize_setup(layer_module, rand_r(&seed), &layer_setup, NULL); + snprintf(layers_path, layers_path_len, "%s/%s", path, "layers"); + for (size_t i = 0; i < s->n_layers; i++) { + const til_module_t *layer_module; + + layer_module = til_lookup_module(((compose_setup_t *)setup)->layers[i].module); ctxt->layers[i].module = layer_module; - (void) til_module_create_context(layer_module, stream, rand_r(&seed), ticks, n_cpus, path, layer_setup, &ctxt->layers[i].module_ctxt); - til_setup_free(layer_setup); + (void) til_module_create_context(layer_module, stream, rand_r(&seed), ticks, n_cpus, layers_path, s->layers[i].setup, &ctxt->layers[i].module_ctxt); /* TODO: errors */ ctxt->n_layers++; } - if (((compose_setup_t *)setup)->texture) { - til_setup_t *texture_setup = NULL; + free(layers_path); + + if (((compose_setup_t *)setup)->texture.module) { + size_t texture_path_len = snprintf(NULL, 0, "%s/%s", path, "texture") + 1; + char *texture_path = calloc(1, texture_path_len); - ctxt->texture.module = til_lookup_module(((compose_setup_t *)setup)->texture); - (void) til_module_randomize_setup(ctxt->texture.module, rand_r(&seed), &texture_setup, NULL); + if (!texture_path) + return til_module_context_free(&ctxt->til_module_context); - (void) til_module_create_context(ctxt->texture.module, stream, rand_r(&seed), ticks, n_cpus, path, texture_setup, &ctxt->texture.module_ctxt); - til_setup_free(texture_setup); + snprintf(texture_path, texture_path_len, "%s/%s", path, "texture"); + + ctxt->texture.module = til_lookup_module(((compose_setup_t *)setup)->texture.module); + (void) til_module_create_context(ctxt->texture.module, stream, rand_r(&seed), ticks, n_cpus, texture_path, s->texture.setup, &ctxt->texture.module_ctxt); /* TODO: errors */ + free(texture_path); } return &ctxt->til_module_context; @@ -113,7 +135,7 @@ static void compose_destroy_context(til_module_context_t *context) { compose_context_t *ctxt = (compose_context_t *)context; - for (int i = 0; i < ctxt->n_layers; i++) + for (size_t i = 0; i < ctxt->n_layers; i++) til_module_context_free(ctxt->layers[i].module_ctxt); if (ctxt->texture.module) @@ -178,7 +200,8 @@ static char * compose_random_layers_setting(unsigned seed) til_get_modules(&modules, &n_modules); for (size_t i = 0; i < n_modules; i++) { - if ((modules[i]->flags & (TIL_MODULE_HERMETIC | TIL_MODULE_EXPERIMENTAL))) { + if ((modules[i]->flags & (TIL_MODULE_HERMETIC | TIL_MODULE_EXPERIMENTAL)) || + modules[i] == &compose_module) { n_unusable++; continue; @@ -190,7 +213,8 @@ static char * compose_random_layers_setting(unsigned seed) base_idx = rand_r(&seed) % (n_modules - (n_overlayable + n_unusable)); for (size_t i = 0, j = 0; !layers && i < n_modules; i++) { - if ((modules[i]->flags & (TIL_MODULE_HERMETIC | TIL_MODULE_EXPERIMENTAL))) + if ((modules[i]->flags & (TIL_MODULE_HERMETIC | TIL_MODULE_EXPERIMENTAL)) || + modules[i] == &compose_module) continue; if (modules[i]->flags & TIL_MODULE_OVERLAYABLE) @@ -210,7 +234,8 @@ static char * compose_random_layers_setting(unsigned seed) size_t rand_idx = rand_r(&seed) % n_overlayable; for (size_t i = 0, j = 0; i < n_modules; i++) { - if ((modules[i]->flags & (TIL_MODULE_HERMETIC | TIL_MODULE_EXPERIMENTAL))) + if ((modules[i]->flags & (TIL_MODULE_HERMETIC | TIL_MODULE_EXPERIMENTAL)) || + modules[i] == &compose_module) continue; if (!(modules[i]->flags & TIL_MODULE_OVERLAYABLE)) @@ -225,7 +250,7 @@ static char * compose_random_layers_setting(unsigned seed) return NULL; } - strcat(new, ":"); + strcat(new, ","); strcat(new, modules[i]->name); layers = new; @@ -238,41 +263,121 @@ static char * compose_random_layers_setting(unsigned seed) } +static void compose_setup_free(til_setup_t *setup) +{ + compose_setup_t *s = (compose_setup_t *)setup; + + if (s) { + for (size_t i = 0; i < s->n_layers; i++) { + free(s->layers[i].module); + til_setup_free(s->layers[i].setup); + } + til_setup_free(s->texture.setup); + free(s->texture.module); + free(setup); + } +} + + static int compose_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 *layers; - const char *texture; - const char *texture_values[] = { - "none", - "blinds", - "checkers", - "drizzle", - "julia", - "moire", - "plasma", - "roto", - "stars", - "submit", - "swab", - "voronoi", - NULL - }; - int r; + const til_settings_t *layers_settings, *texture_settings; + const char *layers; + const char *texture; + const char *texture_values[] = { + "none", + "blinds", + "checkers", + "drizzle", + "julia", + "moire", + "plasma", + "roto", + "stars", + "submit", + "swab", + "voronoi", + NULL + }; + int r; r = til_settings_get_and_describe_value(settings, &(til_setting_spec_t){ - .name = "Colon-separated list of module layers, in draw-order", + .name = "Comma-separated list of module layers, in draw-order", .key = "layers", - .preferred = "drizzle:stars:spiro:plato", + .preferred = "drizzle,stars,spiro,plato", .annotations = NULL, .random = compose_random_layers_setting, + .as_nested_settings = 1, }, - &layers, + &layers, /* XXX: unused in raw-value form, we want the settings instance */ res_setting, res_desc); if (r) return r; + /* once layers is described and present, we reach here, and it should have stored its nested settings instance @ res_settings */ + assert(res_setting && *res_setting && (*res_setting)->value_as_nested_settings); + layers_settings = (*res_setting)->value_as_nested_settings; + { + til_setting_t *layer_setting; + const char *layer; + + /* Now that we have the layers value in its own settings instance, + * iterate across the settings @ layers_settings, turning each of + * those into a nested settings instance as well. + * Ultimately turning layers= into an array of unnamed settings + * instances (they still get automagically labeled as "layers[N]") + */ + + /* + * Note this relies on til_settings_get_value_by_idx() returning NULL once idx runs off the end, + * which is indistinguishable from a NULL-valued setting, so if the user were to fat-finger + * an empty layer like "layers=foo,,bar" maybe we'd never reach bar. This could be made more robust + * by explicitly looking at the number of settings and just ignoring NULL values, but maybe + * instead we should just prohibit such settings constructions? Like an empty value should still get + * "" not NULL put in it. FIXME TODO XXX verify/clarify/assert this in code + */ + for (size_t i = 0; til_settings_get_value_by_idx(layers_settings, i, &layer_setting); i++) { + if (!layer_setting->value_as_nested_settings) { + r = til_setting_desc_new( layers_settings, + &(til_setting_spec_t){ + .as_nested_settings = 1, + }, res_desc); + if (r < 0) + return r; + + *res_setting = layer_setting; + + return 1; + } + } + + /* At this point, whatever layers were provided have now been turned into a settings + * heirarchy. But haven't yet actually resolved the names of and called down into those + * modules' respective setup functions to fully populate the settings as needed. + * + * Again iterate the layers, but this time resolving module names and calling their setup funcs. + * No res_setup is provided here so these will only be building up settings, not producing + * baked setups yet. + */ + for (size_t i = 0; til_settings_get_value_by_idx(layers_settings, i, &layer_setting); i++) { + const char *layer = til_settings_get_value_by_idx(layer_setting->value_as_nested_settings, 0, NULL); + const til_module_t *layer_module = til_lookup_module(layer); + + if (!layer_module) + return -EINVAL; + + if (layer_module->setup) { + r = layer_module->setup(layer_setting->value_as_nested_settings, res_setting, res_desc, NULL); + if (r) + return r; + } + } + + /* at this point all the layers should have all their settings built up in their respective settings instances */ + } + r = til_settings_get_and_describe_value(settings, &(til_setting_spec_t){ .name = "Module to use for source texture, \"none\" to disable", @@ -280,6 +385,7 @@ static int compose_setup(const til_settings_t *settings, til_setting_t **res_set .preferred = texture_values[0], .annotations = NULL, .values = texture_values, + .as_nested_settings = 1, }, &texture, res_setting, @@ -287,84 +393,88 @@ static int compose_setup(const til_settings_t *settings, til_setting_t **res_set if (r) return r; - /* turn layers colon-separated list into a null-terminated array of strings */ - if (res_setup) { - compose_setup_t *setup; - const til_module_t **modules; - size_t n_modules; - char *toklayers, *layer; - int n = 2; + assert(res_setting && *res_setting && (*res_setting)->value_as_nested_settings); + texture_settings = (*res_setting)->value_as_nested_settings; + if (strcasecmp(texture, "none")) { + const char *texture = til_settings_get_value_by_idx(texture_settings, 0, NULL); + const til_module_t *texture_module = til_lookup_module(texture); - til_get_modules(&modules, &n_modules); + if (!texture_module) + return -EINVAL; - toklayers = strdup(layers); - if (!toklayers) - return -ENOMEM; + if (texture_module->setup) { + r = texture_module->setup(texture_settings, res_setting, res_desc, NULL); + if (r) + return r; + } - layer = strtok(toklayers, ":"); - if (!layer) - return -EINVAL; + /* now texture settings are complete, but not yet baked (no res_setup) */ + } - setup = til_setup_new(sizeof(*setup), (void(*)(til_setup_t *))free); + if (res_setup) { /* turn layers settings into an array of compose_setup_layer_t's {name,til_setup_t} */ + size_t n_layers = til_settings_get_count(layers_settings); + til_setting_t *layer_setting; + compose_setup_t *setup; + + setup = til_setup_new(sizeof(*setup) + n_layers * sizeof(*setup->layers), compose_setup_free); if (!setup) return -ENOMEM; - do { - compose_setup_t *new; - size_t i; - - /* other meta-modules like montage and rtv may need to - * have some consideration here, but for now I'm just - * going to let the user potentially compose with montage - * or rtv as one of the layers. - */ - if (!strcasecmp(layer, "compose")) { /* XXX: prevent infinite recursion */ - til_setup_free(&setup->til_setup); - - return -EINVAL; - } + setup->n_layers = n_layers; - for (i = 0; i < n_modules; i++) { - if (!strcasecmp(layer, modules[i]->name)) - break; - } + for (size_t i = 0; til_settings_get_value_by_idx(layers_settings, i, &layer_setting); i++) { + const char *layer = til_settings_get_value_by_idx(layer_setting->value_as_nested_settings, 0, NULL); + const til_module_t *layer_module = til_lookup_module(layer); - if (i >= n_modules) { + if (!layer_module) { til_setup_free(&setup->til_setup); return -EINVAL; } - new = realloc(setup, sizeof(*setup) + n * sizeof(*setup->layers)); - if (!new) { + setup->layers[i].module = strdup(layer); + if (!setup->layers[i].module) { til_setup_free(&setup->til_setup); return -ENOMEM; } - new->layers[n - 2] = layer; - new->layers[n - 1] = NULL; - n++; + if (layer_module->setup) { + r = layer_module->setup(layer_setting->value_as_nested_settings, res_setting, res_desc, &setup->layers[i].setup); + if (r < 0) { + til_setup_free(&setup->til_setup); - setup = new; - } while ((layer = strtok(NULL, ":"))); + return r; + } + } + } if (strcasecmp(texture, "none")) { - const til_module_t *texture_module; + const char *texture = til_settings_get_value_by_idx(texture_settings, 0, NULL); + const til_module_t *texture_module = til_lookup_module(texture); - texture_module = til_lookup_module(texture); if (!texture_module) { til_setup_free(&setup->til_setup); return -EINVAL; } - setup->texture = strdup(texture); - if (!setup->texture) { + setup->texture.module = strdup(texture); + if (!setup->texture.module) { til_setup_free(&setup->til_setup); return -ENOMEM; } + + if (texture_module->setup) { + /* bake the texture settings */ + r = texture_module->setup(texture_settings, res_setting, res_desc, &setup->texture.setup); + if (r < 0) { + til_setup_free(&setup->til_setup); + + return r; + } + } } *res_setup = &setup->til_setup; |