diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2019-05-09 19:40:42 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2019-05-10 14:18:28 -0700 |
commit | 277ead61dc5ff6bba1035acf7b6e194e6de739ad (patch) | |
tree | 7cc093ff4aed45085e10b1412939c254e6a1dfd9 | |
parent | 049d14269ac518135a278132efe2ac01f92482e6 (diff) |
libstage: deprecate stage_node_*, go heirarchical
Now stage_t is the only type, and a tree of stages may be
constructed by supplying a parent to stage_new().
Essentially stage_t swallowed stage_node_t.
The heirarchy is handy for grouping stages logically, and alpha
is computed statefully during the recursive render. So alpha of
grouped stages may be varied at a single parent. The active
flag is also honored recursively for a similar effect; toggle
subtrees in a single place.
Container stages may be created by omitting object/render/free
attributes. These are handy for the aforementioned group
alpha/active controls.
-rw-r--r-- | src/stage.c | 268 | ||||
-rw-r--r-- | src/stage.h | 34 |
2 files changed, 139 insertions, 163 deletions
diff --git a/src/stage.c b/src/stage.c index d97cadf..806b633 100644 --- a/src/stage.c +++ b/src/stage.c @@ -22,191 +22,181 @@ #include "stage.h" -struct stage_node_t { - dll_t nodes; - char name[STAGE_NODE_NAME_MAX]; - float alpha; /* alpha for the texture when composited */ - unsigned active:1; /* node is active */ - unsigned locked:1; /* node is locked */ - - stage_render_func_t render; /* render object into a texture */ +struct stage_t { + stage_t *parent; /* NULL when root stage */ + dll_t layer; /* node on parent->layers[layer] when parent != NULL */ + dll_t layers[STAGE_LAYERS_MAX]; + char name[STAGE_NAME_MAX]; + float alpha; /* alpha for the stage */ + unsigned active:1; /* stage is active */ + unsigned locked:1; /* stage is locked */ + + stage_render_func_t render; /* render object */ stage_free_func_t free; /* free object */ void *object; /* object */ }; -struct stage_t { - dll_t layers[STAGE_LAYERS_MAX]; - float alpha; /* alpha to apply to all nodes */ -}; - - -/* minimally initialize a node to carry an object */ -static void node_init(stage_node_t *node, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func) +/* minimally initialize a stage to carry an object */ +static void _stage_set_object(stage_t *stage, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func) { - strncpy(node->name, name, sizeof(node->name)); - node->render = render_func; - node->free = free_func; - node->object = object; + strncpy(stage->name, name, sizeof(stage->name)); + stage->render = render_func; + stage->free = free_func; + stage->object = object; } -/* allocate a node, no list manipulation occurs, this purely creates a node in isolation and assigns its associated name, object and functions */ -static stage_node_t * node_new(const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func) +/* allocate a stage, this purely creates a stage in isolation and assigns its associated name, object and functions */ +static stage_t * _stage_new(const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func) { - stage_node_t *node; + stage_t *stage; - node = calloc(1, sizeof(stage_node_t)); - if (!node) + stage = calloc(1, sizeof(stage_t)); + if (!stage) return NULL; - node_init(node, name, object, render_func, free_func); + dll_init(&stage->layer); + for (int i = 0; i < STAGE_LAYERS_MAX; i++) + dll_init(&stage->layers[i]); - return node; + _stage_set_object(stage, name, object, render_func, free_func); + + return stage; } -/* free a node, no list manipulation occurs, this is purely cleanup of the node and its associated texture and object */ -static void node_free(stage_t *stage, stage_node_t *node) +/* free a stage, no list manipulation occurs, this is purely cleanup of the stage and its object */ +static void _stage_free(stage_t *stage) { - if (node->free) - node->free(stage, node, node->object); + if (stage->free) + stage->free(stage, stage->object); - free(node); + free(stage); } -/* returns a new node installed at the specified layer */ -stage_node_t * stage_node_new(stage_t *stage, int layer, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func) +/* returns a new stage, attached at the specified layer under parent if supplied */ +/* layer has no effect when parent == NULL */ +stage_t * stage_new(stage_t *parent, int layer, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func) { - stage_node_t *node; + stage_t *stage; - node = node_new(name, object, render_func, free_func); - if (!node) + stage = _stage_new(name, object, render_func, free_func); + if (!stage) return NULL; - (void) dll_add_pre(&node->nodes, &stage->layers[layer]); + if (parent) { + stage->parent = parent; + (void) dll_add_pre(&parent->layers[layer], &stage->layer); + } - return node; + return stage; } -/* replace a given node's object only - retain render/free hooks and everything else, invalidates cache - DOES NOT FREE OLD OBJECT */ -void stage_node_set_object(const stage_t *stage, stage_node_t *node, void *object) +/* replace a given stage's object only - retain render/free hooks and everything else, invalidates cache - DOES NOT FREE OLD OBJECT */ +void stage_set_object(stage_t *stage, void *object) { - node->object = object; + stage->object = object; } -void stage_node_get_object(const stage_t *stage, stage_node_t *node, void **res_object) +void stage_get_object(const stage_t *stage, void **res_object) { - *res_object = node->object; + *res_object = stage->object; } -/* replaces a given node's object-related properties but otherwise keeping the existing state */ -void stage_node_replace(const stage_t *stage, stage_node_t *node, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func) +/* replaces a given stage's object-related properties but otherwise keeping the existing state */ +void stage_replace(stage_t *stage, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func) { - if (node->free) - node->free(stage, node, node->object); + if (stage->free) + stage->free(stage, stage->object); - node_init(node, name, object, render_func, free_func); + _stage_set_object(stage, name, object, render_func, free_func); } -/* frees a given node removing it from the stage */ -stage_node_t * stage_node_free(stage_t *stage, stage_node_t *node) +static void _stage_free_all(stage_t *stage, int force); + + +/* recursively free the layers of this stage, but not the stage itself */ +static void _stage_free_layers(stage_t *stage, int force) { - if (node) { - (void) dll_del(&node->nodes); - node_free(stage, node); - } + for (int i = 0; i < STAGE_LAYERS_MAX; i++) { + stage_t *s, *_s; - return NULL; + DLL_FOR_EACH_ENTRY_SAFE(&stage->layers[i], s, _s, stage_t, layer) + _stage_free_all(s, force); + } } -/* set the alpha on a node */ -void stage_node_set_alpha(const stage_t *stage, stage_node_t *node, float alpha) +/* free the stage recursively, skipping locked stages if !force */ +static void _stage_free_all(stage_t *stage, int force) { - /* TODO: this should probably mark something dirty for when we stop always recomposing everything */ - node->alpha = alpha; + if (stage->locked && !force) + return; + + _stage_free_layers(stage, force); + dll_del(&stage->layer); + _stage_free(stage); } -/* set a node's active state (participates in rendering) */ -void stage_node_set_active(const stage_t *stage, stage_node_t *node, int active) +/* frees a given stage and all its descendants, removing from its + * parent if not root. + */ +stage_t * stage_free(stage_t *stage) { - node->active = active; + if (stage) + _stage_free_all(stage, 1); + + return NULL; } -/* set a node's locked state (doesn't get freed by clears) */ -void stage_node_set_locked(const stage_t *stage, stage_node_t *node, int locked) +/* set the alpha on a stage */ +void stage_set_alpha(stage_t *stage, float alpha) { - node->locked = locked; + stage->alpha = alpha; } -/* set a node's layer */ -void stage_node_set_layer(stage_t *stage, stage_node_t *node, int layer) +/* set a stage's active state (participates in rendering) */ +void stage_set_active(stage_t *stage, int active) { - /* TODO: assert layer sanity */ - (void) dll_del(&node->nodes); - (void) dll_add_pre(&node->nodes, &stage->layers[layer]); + stage->active = active; } -/* create a new stage with the given aspect ratio */ -stage_t * stage_new(void) +/* set a stage's locked state (doesn't get freed by clears) */ +void stage_set_locked(stage_t *stage, int locked) { - stage_t *stage; - int i; - - stage = calloc(1, sizeof(stage_t)); - if (!stage) - return NULL; - - for (i = 0; i < STAGE_LAYERS_MAX; i++) - (void) dll_init(&stage->layers[i]); - - return stage; + stage->locked = locked; } -static void _stage_clear(stage_t *stage, int force) +/* set a stage's layer (must not be root stage) */ +/* TODO: maybe support supplying a parent here for switching parents? */ +void stage_set_layer(stage_t *stage, int layer) { - stage_node_t *node, *_node; - int i; - - for (i = 0; i < STAGE_LAYERS_MAX; i++) { - DLL_FOR_EACH_ENTRY_SAFE(&stage->layers[i], node, _node, stage_node_t, nodes) { - if (force || !node->locked) - stage_node_free(stage, node); - } + /* TODO: assert parent, and layer sanity */ + if (stage->parent) { + (void) dll_del(&stage->layer); + (void) dll_add_pre(&stage->parent->layers[layer], &stage->layer); } } + /* free everything in the stage, but keep the stage around */ /* probably good hygiene to clear everything when there's no intention of - * reusing nodes at the start of a new context, in case something is left + * reusing stages at the start of a new context, in case something is left * around unintentionally. */ void stage_clear(stage_t *stage) { - _stage_clear(stage, 0); -} - - -/* free the supplied stage and all associated textures and objects */ -stage_t * stage_free(stage_t *stage) -{ - - if (stage) { - _stage_clear(stage, 1); - free(stage); - } - - return NULL; + _stage_free_layers(stage, 0); } @@ -232,58 +222,50 @@ void stage_fit(float aspect_ratio, int width, int height, int *res_width, int *r } -/* set the global alpha factor for the stage, the individual node alphas are multiplied by this value @ render time. */ -void stage_set_alpha(stage_t *stage, float alpha) -{ - stage->alpha = alpha; -} - - -/* get the global alpha factor for the stage */ -void stage_get_alpha(stage_t *stage, float *res_alpha) +static void _render_stage(const stage_t *stage, float alpha) { - *res_alpha = stage->alpha; -} + float a = alpha * stage->alpha; + if (stage->render) + stage->render(stage, stage->object, a); -static void render_nodes(const stage_t *stage, const dll_t *nodes) -{ - stage_node_t *node; + for (int i = 0; i < STAGE_LAYERS_MAX; i++) { + stage_t *s; - DLL_FOR_EACH_ENTRY(nodes, node, stage_node_t, nodes) { - if (!node->active) - continue; + DLL_FOR_EACH_ENTRY(&stage->layers[i], s, stage_t, layer) { + if (!s->active) + continue; - node->render(stage, node, node->object, stage->alpha * node->alpha); + _render_stage(s, a); + } } } -/* render the supplied stage into the supplied renderer */ -/* the aspect_ratio of the stage will be enforced in filling the logical size - * of the renderer. Unless the aspect ratio matches precisely, stage_render() - * will center the rendering and leave blank borders on the edges left empty. - * The renderer may be sized precisely by first calling stage_fit(). - */ +/* recursively render the supplied stage tree, skipping inactive branches */ void stage_render(const stage_t *stage) { - int i; + if (!stage->active) + return; - for (i = 0; i < STAGE_LAYERS_MAX; i++) - render_nodes(stage, &stage->layers[i]); + _render_stage(stage, 1.f); } -/* lookup a node from a name */ -stage_node_t * stage_node_lookup_name(const stage_t *stage, const char *name) +/* lookup a stage from a name, returns first match */ +stage_t * stage_lookup_name(stage_t *stage, const char *name) { - stage_node_t *node; - int i; + if (!strncmp(stage->name, name, sizeof(stage->name))) + return stage; + + /* FIXME: this should probably search layers in descending order */ + for (int i = 0; i < STAGE_LAYERS_MAX; i++) { + stage_t *s; - for (i = 0; i < STAGE_LAYERS_MAX; i++) { - DLL_FOR_EACH_ENTRY(&stage->layers[i], node, stage_node_t, nodes) { - if (!strncmp(node->name, name, sizeof(node->name))) - return node; + DLL_FOR_EACH_ENTRY(&stage->layers[i], s, stage_t, layer) { + s = stage_lookup_name(s, name); + if (s) + return s; } } diff --git a/src/stage.h b/src/stage.h index 942174a..8357206 100644 --- a/src/stage.h +++ b/src/stage.h @@ -17,32 +17,26 @@ #ifndef _STAGE_H #define _STAGE_H -#define STAGE_NODE_NAME_MAX 16 +#define STAGE_NAME_MAX 16 #define STAGE_LAYERS_MAX 10 typedef struct stage_t stage_t; -typedef struct stage_node_t stage_node_t; -typedef void (*stage_render_func_t)(const stage_t *stage, const stage_node_t *node, void *object, float alpha); -typedef void (*stage_free_func_t)(const stage_t *stage, const stage_node_t *node, void *object); +typedef void (*stage_render_func_t)(const stage_t *stage, void *object, float alpha); +typedef void (*stage_free_func_t)(const stage_t *stage, void *object); -stage_t * stage_new(void); -void stage_clear(stage_t *stage); +stage_t * stage_new(stage_t *parent, int layer, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func); stage_t * stage_free(stage_t *stage); -void stage_fit(float aspect_ratio, int width, int height, int *res_width, int *res_height); -void stage_set_alpha(stage_t *stage, float alpha); -void stage_get_alpha(stage_t *stage, float *res_alpha); void stage_render(const stage_t *stage); -stage_node_t * stage_node_new(stage_t *stage, int layer, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func); - -void stage_node_set_object(const stage_t *stage, stage_node_t *node, void *object); -void stage_node_get_object(const stage_t *stage, stage_node_t *node, void **res_object); -void stage_node_replace(const stage_t *stage, stage_node_t *node, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func); -stage_node_t * stage_node_free(stage_t *stage, stage_node_t *node); -void stage_node_set_alpha(const stage_t *stage, stage_node_t *node, float alpha); -void stage_node_set_active(const stage_t *stage, stage_node_t *node, int active); -void stage_node_set_locked(const stage_t *stage, stage_node_t *node, int locked); -void stage_node_set_layer(stage_t *stage, stage_node_t *node, int layer); -stage_node_t * stage_node_lookup_name(const stage_t *stage, const char *name); +void stage_clear(stage_t *stage); +void stage_set_alpha(stage_t *stage, float alpha); +void stage_get_alpha(const stage_t *stage, float *res_alpha); +void stage_set_active(stage_t *stage, int active); +void stage_set_locked(stage_t *stage, int locked); +void stage_set_object(stage_t *stage, void *object); +void stage_get_object(const stage_t *stage, void **res_object); +void stage_replace(stage_t *stage, const char *name, void *object, stage_render_func_t render_func, stage_free_func_t free_func); +void stage_set_layer(stage_t *stage, int layer); +stage_t * stage_lookup_name(stage_t *stage, const char *name); #endif |