diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2023-01-08 22:01:45 -0800 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2023-01-09 15:14:04 -0800 |
commit | 63a915404efa32677460fd1d3388a1aae3924d2b (patch) | |
tree | 003b823eea7490742a608e303aa6810c1ad3007f /src | |
parent | 1bea12c3087bf6716ee9749051ee8866bb2184ba (diff) |
til_tap: first stab at a tap interface
The idea here is for modules to bind variables to names @ context
create time w/til_tap_new(). Pseudo-code sample:
```
typedef struct foo_context_t {
struct {
til_tap_t *position;
} taps;
struct {
v2f_t position;
} vars;
v2f_t *position;
} foo_context_t;
foo_context_t * foo_create_context(void)
{
foo_context_t *foo = malloc(sizeof(foo_context_t));
/* This creates an isolated (pipe-)tap binding our local position variable and pointer
* to a name for later "tapping" onto a stream.
*/
foo->taps.position = til_tap_new_v2f(&foo->position, "position", 1, &foo->vars.position);
return foo;
}
foo_render(foo_context_t *foo, til_fb_fragment_t *fragment)
{
if (!til_stream_tap(fragment->stream, &foo->pipes.position)) {
/* got nothing, we're driving */
foo->position->x = cosf(ticks);
foo->position->y = sinf(ticks);
} /* else { got something, just use foo->position as-is */
draw_stuff_using_position(foo->position);
}
```
Note til_stream_tap() doesn't exist yet, this commit only adds
the tap (til_tap_new()).
The stream will probably implement a hash table for looking up
the tap by name, verifying its type and nelems match if found,
and update the pointer to point at the instance actually driving
for the name. (in the example that's the foo_context_t.position
pointer which draw_stuff_using_position() then dereferences)
Also note that in the example, "position" alone is too simplistic
for handling complex real-life compositions where a given module
may recur in a given stream. That identifier would need to be
derived from the module's context/setup producing a distinctly
unique path to the tap. i.e.
"/compose/layers/checkers/fill_module/foo:position" or something,
to be dynamically generated. And the foo:position syntax isn't
set in stone either. Maybe foo/position would suffice, the whole
heirarchical syntax needs to be thought through and defined yet.
Since the absolute path to the tap would be setup-dependent, there
will have to be some glue tying together the setup used by the
context and the tap within that context. The stream may be the
natural place where that occurs.
This also currently is barebones in terms of the tap types
supported. The only higher-order types are rudimentary 2-4d
vectors and 4x4 matrices. There are no semantics associated
with the types, and it's likely in the future either the tap
types themselves will expand to be semantic. Think things like
a camera type, composed both a point and direction vector.
As-is the few higher-order types in til_tap.h are simply forward
declared, and at least in terms of the taps alone further type
visibility isn't necessary.
It may make more sense to build upon these bare taps with another
semantic layer bringing the higher-order types to the table in a
more concrete form. All those higher-order types would then be
composed from the bare taps.
There's some conceptual overlap with the knobs stubbed out in
til_knobs.h as well. I think this likely at least partially
replaces what's there, and what it doesn't will probably end up
somewhere else.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/til_tap.c | 70 | ||||
-rw-r--r-- | src/til_tap.h | 117 |
3 files changed, 188 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 88cd43d..3b6c0f0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = libs modules noinst_LTLIBRARIES = libtil.la -libtil_la_SOURCES = til_args.c til_args.h til_fb.c til_fb.h til_knobs.h til.c til.h til_module_context.c til_module_context.h til_settings.h til_settings.c til_setup.c til_setup.h til_threads.c til_threads.h til_util.c til_util.h +libtil_la_SOURCES = til_args.c til_args.h til_fb.c til_fb.h til_knobs.h til.c til.h til_module_context.c til_module_context.h til_settings.h til_settings.c til_setup.c til_setup.h til_tap.c til_tap.h til_threads.c til_threads.h til_util.c til_util.h libtil_la_CPPFLAGS = -I@top_srcdir@/src libtil_la_LIBADD = modules/blinds/libblinds.la modules/checkers/libcheckers.la modules/compose/libcompose.la modules/drizzle/libdrizzle.la modules/flui2d/libflui2d.la modules/julia/libjulia.la modules/meta2d/libmeta2d.la modules/moire/libmoire.la modules/montage/libmontage.la modules/pixbounce/libpixbounce.la modules/plasma/libplasma.la modules/plato/libplato.la modules/ray/libray.la modules/roto/libroto.la modules/rtv/librtv.la modules/shapes/libshapes.la modules/snow/libsnow.la modules/sparkler/libsparkler.la modules/spiro/libspiro.la modules/stars/libstars.la modules/strobe/libstrobe.la modules/submit/libsubmit.la modules/swab/libswab.la modules/swarm/libswarm.la modules/voronoi/libvoronoi.la libs/grid/libgrid.la libs/puddle/libpuddle.la libs/ray/libray.la libs/sig/libsig.la libs/txt/libtxt.la libs/ascii/libascii.la libs/din/libdin.la diff --git a/src/til_tap.c b/src/til_tap.c new file mode 100644 index 0000000..44550b6 --- /dev/null +++ b/src/til_tap.c @@ -0,0 +1,70 @@ +#include <assert.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "til_tap.h" + +/* A "tap" is a named binding of a local variable+pointer to that variable. + * + * It's purpose is to facilitate exposing local variables controlling rendering + * to potential external influence. + * + * While the tap alone does get named, this is mostly for ergonomic reasons since + * it's convenient and natural to name the tap while specifying its variable and + * pointer by name as well. Putting them all in once place. + * + * The tap itself is not a registry or otherwise discoverable entity by itself. + * This is strictly just the local glue, with a name. Other pieces must tie taps + * into streams or settings stuff for addressing them by name at a path or other + * means. + * + * Note the intended way for taps to work is that the caller will always access their + * local variables indirectly via the pointers they provided when creating the taps. + * There will be a function for managing the tap the caller must call before accessing + * the variable indirectly as well. It's that function which will update the indirection + * pointer to potentially point elsewhere if another tap is driving the variable. + */ + +struct til_tap_t { + til_tap_type_t type; + void *ptr; /* points at the caller-provided tap-managed indirection pointer */ + size_t n_elems; /* when > 1, *ptr is an array of n_elems elements. Otherwise individual variable. */ + void *elems; /* points at the first element of type type, may or may not be an array of them */ + char name[]; +}; + + +/* This is the raw tap creator but use the type-checked wrappers in the header and add one if one's missing */ +til_tap_t * til_tap_new(til_tap_type_t type, void *ptr, const char *name, size_t n_elems, void *elems) +{ + til_tap_t *tap; + + assert(name); + assert(type < TIL_TAP_TYPE_MAX); + assert(ptr); + assert(n_elems); + assert(elems); + + tap = calloc(1, sizeof(til_tap_t) + strlen(name) + 1); + if (!tap) + return NULL; + + strcpy(tap->name, name); + tap->type = type; + tap->ptr = ptr; + tap->n_elems = n_elems; + tap->elems = elems; + + *((void **)tap->ptr) = elems; + + return tap; +} + + +til_tap_t * til_tap_free(til_tap_t *tap) +{ + free(tap); + + return NULL; +} diff --git a/src/til_tap.h b/src/til_tap.h new file mode 100644 index 0000000..b9de6d9 --- /dev/null +++ b/src/til_tap.h @@ -0,0 +1,117 @@ +#ifndef _TIL_TAP_H +#define _TIL_TAP_H + +#include <stdint.h> + +/* These are all the supported tap types, nothing is set in stone this just + * seemed like the likely stuff to need. Feel free to add anything as needed. + */ +typedef enum til_tap_type_t { + TIL_TAP_TYPE_I8, + TIL_TAP_TYPE_I16, + TIL_TAP_TYPE_I32, + TIL_TAP_TYPE_I64, + TIL_TAP_TYPE_U8, + TIL_TAP_TYPE_U16, + TIL_TAP_TYPE_U32, + TIL_TAP_TYPE_U64, + TIL_TAP_TYPE_FLOAT, + TIL_TAP_TYPE_DOUBLE, + TIL_TAP_TYPE_V2F, /* 2D vector of floats */ + TIL_TAP_TYPE_V3F, /* 3D vector of floats */ + TIL_TAP_TYPE_V4F, /* 4D vector of floats */ + TIL_TAP_TYPE_M4F, /* 4x4 float matrix */ + TIL_TAP_TYPE_VOIDP, /* escape hatch for when you're getting exotic and want to bypass type checking */ + TIL_TAP_TYPE_MAX, +} til_tap_type_t; + +typedef struct til_tap_t til_tap_t; + +til_tap_t * til_tap_new(til_tap_type_t type, void *ptr, const char *name, size_t n_elems, void *elems); +til_tap_t * til_tap_free(til_tap_t *tap); + +/* just some forward declared higher-order vector and matrix types for the wrappers */ +typedef struct v2f_t v2f_t; +typedef struct v3f_t v3f_t; +typedef struct v4f_t v4f_t; +typedef struct m4f_t m4f_t; + +/* typed wrappers, just supply n_elems=1 for individual variables - note n_elems is just a defensive + * programming sanity check to catch callers mismatching array sizes + */ +static inline til_tap_t * til_tap_new_i8(int8_t **ptr, const char *name, size_t n_elems, int8_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_I8, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_i16(int16_t **ptr, const char *name, size_t n_elems, int16_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_I16, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_i32(int32_t **ptr, const char *name, size_t n_elems, int32_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_I32, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_i64(int64_t **ptr, const char *name, size_t n_elems, int64_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_I64, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_u8(uint8_t **ptr, const char *name, size_t n_elems, uint8_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_U8, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_u16(uint16_t **ptr, const char *name, size_t n_elems, uint16_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_U16, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_u32(uint32_t **ptr, const char *name, size_t n_elems, uint32_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_U32, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_u64(uint64_t **ptr, const char *name, size_t n_elems, uint64_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_U64, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_float(float **ptr, const char *name, size_t n_elems, float *elems) +{ + return til_tap_new(TIL_TAP_TYPE_FLOAT, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_double(double **ptr, const char *name, size_t n_elems, double *elems) +{ + return til_tap_new(TIL_TAP_TYPE_DOUBLE, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_v2f(v2f_t **ptr, const char *name, size_t n_elems, v2f_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_V2F, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_v3f(v3f_t **ptr, const char *name, size_t n_elems, v3f_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_V3F, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_v4f(v4f_t **ptr, const char *name, size_t n_elems, v4f_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_V4F, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_m4f(m4f_t **ptr, const char *name, size_t n_elems, m4f_t *elems) +{ + return til_tap_new(TIL_TAP_TYPE_M4F, ptr, name, n_elems, elems); +} + +static inline til_tap_t * til_tap_new_voidp(void **ptr, const char *name, size_t n_elems, void *elems) +{ + return til_tap_new(TIL_TAP_TYPE_VOIDP, ptr, name, n_elems, elems); +} + +#endif |